Paul Martin
2016-04-27 c2188a840bc4153ae92112b04b2e06a90d3944aa
src/main/java/com/gitblit/tickets/RedisTicketService.java
@@ -20,6 +20,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
@@ -32,6 +33,7 @@
import com.gitblit.Keys;
import com.gitblit.manager.INotificationManager;
import com.gitblit.manager.IPluginManager;
import com.gitblit.manager.IRepositoryManager;
import com.gitblit.manager.IRuntimeManager;
import com.gitblit.manager.IUserManager;
@@ -41,6 +43,8 @@
import com.gitblit.models.TicketModel.Change;
import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.StringUtils;
import com.google.inject.Inject;
import com.google.inject.Singleton;
/**
 * Implementation of a ticket service based on a Redis key-value store.  All
@@ -51,6 +55,7 @@
 * @author James Moger
 *
 */
@Singleton
public class RedisTicketService extends ITicketService {
   private final JedisPool pool;
@@ -59,13 +64,16 @@
      journal, ticket, counter
   }
   @Inject
   public RedisTicketService(
         IRuntimeManager runtimeManager,
         IPluginManager pluginManager,
         INotificationManager notificationManager,
         IUserManager userManager,
         IRepositoryManager repositoryManager) {
      super(runtimeManager,
            pluginManager,
            notificationManager,
            userManager,
            repositoryManager);
@@ -76,6 +84,10 @@
   @Override
   public RedisTicketService start() {
      log.info("{} started", getClass().getSimpleName());
      if (!isReady()) {
         log.warn("{} is not ready!", getClass().getSimpleName());
      }
      return this;
   }
@@ -168,7 +180,7 @@
      }
      try {
         Boolean exists = jedis.exists(key(repository, KeyType.journal, ticketId));
         return exists != null && !exists;
         return exists != null && exists;
      } catch (JedisException e) {
         log.error("failed to check hasTicket from Redis @ " + getUrl(), e);
         pool.returnBrokenResource(jedis);
@@ -179,6 +191,30 @@
         }
      }
      return false;
   }
   @Override
   public Set<Long> getIds(RepositoryModel repository) {
      Set<Long> ids = new TreeSet<Long>();
      Jedis jedis = pool.getResource();
      try {// account for migrated tickets
         Set<String> keys = jedis.keys(key(repository, KeyType.journal, "*"));
         for (String tkey : keys) {
            // {repo}:journal:{id}
            String id = tkey.split(":")[2];
            long ticketId = Long.parseLong(id);
            ids.add(ticketId);
         }
      } catch (JedisException e) {
         log.error("failed to assign new ticket id in Redis @ " + getUrl(), e);
         pool.returnBrokenResource(jedis);
         jedis = null;
      } finally {
         if (jedis != null) {
            pool.returnResource(jedis);
         }
      }
      return ids;
   }
   /**
@@ -194,7 +230,14 @@
         String key = key(repository, KeyType.counter, null);
         String val = jedis.get(key);
         if (isNull(val)) {
            jedis.set(key, "0");
            long lastId = 0;
            Set<Long> ids = getIds(repository);
            for (long id : ids) {
               if (id > lastId) {
                  lastId = id;
               }
            }
            jedis.set(key, "" + lastId);
         }
         long ticketNumber = jedis.incr(key);
         return ticketNumber;
@@ -270,8 +313,7 @@
   }
   /**
    * Retrieves the ticket from the repository by first looking-up the changeId
    * associated with the ticketId.
    * Retrieves the ticket from the repository.
    *
    * @param repository
    * @param ticketId
@@ -309,6 +351,39 @@
   }
   /**
    * Retrieves the journal for the ticket.
    *
    * @param repository
    * @param ticketId
    * @return a journal, if it exists, otherwise null
    */
   @Override
   protected List<Change> getJournalImpl(RepositoryModel repository, long ticketId) {
      Jedis jedis = pool.getResource();
      if (jedis == null) {
         return null;
      }
      try {
         List<Change> changes = getJournal(jedis, repository, ticketId);
         if (ArrayUtils.isEmpty(changes)) {
            log.warn("Empty journal for {}:{}", repository, ticketId);
            return null;
         }
         return changes;
      } catch (JedisException e) {
         log.error("failed to retrieve journal from Redis @ " + getUrl(), e);
         pool.returnBrokenResource(jedis);
         jedis = null;
      } finally {
         if (jedis != null) {
            pool.returnResource(jedis);
         }
      }
      return null;
   }
   /**
    * Returns the journal for the specified ticket.
    *
    * @param repository