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); } } }