content: package com.airbnb.airpal.core.store.history;
  
  import com.airbnb.airpal.api.EvictingDeque;
  import com.airbnb.airpal.api.Job;
  import com.airbnb.airpal.presto.Table;
  import com.google.common.cache.Cache;
  import com.google.common.cache.CacheBuilder;
  import com.google.common.collect.ImmutableList;
  import com.google.common.collect.Lists;
  
  import java.util.List;
  import java.util.Map;
  import java.util.concurrent.LinkedBlockingDeque;
  
  public class LocalJobHistoryStore implements JobHistoryStore {
  
      public static class FinishedJobEvictingDeque extends EvictingDeque<Job> {
          public FinishedJobEvictingDeque(int capacity) {
              super(capacity);
          }
  
          @Override
          protected boolean evictItem(LinkedBlockingDeque<Job> deque) {
              final Job job = deque.poll();
  
              if (job != null) {
                  if (job.getState().isDone()) {
                      return true;
                  } else {
                      boolean addResult = add(job);
                      boolean secondEviction = evictItem(deque);
  
                      return addResult && secondEviction;
                  }
              } else {
                  return false;
              }
          }
      }
  
      private final Cache<Table, EvictingDeque<Job>> tableHistoryCache;
      private final EvictingDeque<Job> historyCache;
      private final int maximumHistoryPerTable;
  
      public LocalJobHistoryStore(final long maximumTableHistories,
                                  final int maximumHistoryPerTable,
                                  final long maximumHistoryGeneral)
      {
          this.tableHistoryCache = CacheBuilder.newBuilder()
                                               .maximumSize(maximumTableHistories)
                                               .build();
  
          this.historyCache = new FinishedJobEvictingDeque((int)maximumHistoryGeneral);
  
          this.maximumHistoryPerTable = maximumHistoryPerTable;
      }
  
      @Override
      public List<Job> getRecentlyRun(long maxResults) {
          final ImmutableList.Builder<Job> builder = ImmutableList.builder();
          long added = 0;
  
          for (Job job : historyCache) {
              if (added + 1 > maxResults)
                  break;
  
              builder.add(job);
              added += 1;
          }
  
          return builder.build();
      }
  
      @Override
      public List<Job> getRecentlyRun(long maxResults, Table table1, Table... otherTables)
      {
          return getRecentlyRun(maxResults, Lists.asList(table1, otherTables));
      }
  
      @Override
      public List<Job> getRecentlyRunForUser(String user, long maxResults)
      {
          return null;
      }
  
      @Override
      public List<Job> getRecentlyRunForUser(String user, long maxResults, Iterable<Table> tables)
      {
          return null;
      }
  
      @Override
      public List<Job> getRecentlyRun(long maxResults, Iterable<Table> tables)
      {
          final ImmutableList.Builder<Job> builder = ImmutableList.builder();
          long added = 0;
  
          for (Map.Entry<Table, EvictingDeque<Job>> entry : tableHistoryCache.getAllPresent(tables).entrySet()) {
              EvictingDeque<Job> deque = entry.getValue();
              if (deque != null) {
                  final int dequeSize = deque.size();
                  if (added + dequeSize > maxResults) {
                      break;
                  } else {
                      builder.addAll(deque);
                      added += dequeSize;
                  }
              }
          }
  
          return builder.build();
      }
  
      @Override
      public void addRun(Job job) {
          historyCache.add(job);
  
          for (Table usedTable : job.getTablesUsed()) {
              EvictingDeque<Job> tableCache = tableHistoryCache.getIfPresent(usedTable);
  
              if (tableCache == null) {
                  tableCache = new FinishedJobEvictingDeque(maximumHistoryPerTable);
                  tableHistoryCache.put(usedTable, tableCache);
              }
  
              tableCache.add(job);
          }
      }
  }
  