Java tutorial
/* Copyright (c) 2015-2016 Boundless and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Distribution License v1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/edl-v10.html * * Contributors: * Gabriel Roldan (Boundless) - initial implementation */ package org.locationtech.geogig.model.internal; import java.util.Iterator; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicInteger; import org.locationtech.geogig.model.ObjectId; import org.locationtech.geogig.model.RevTree; import org.locationtech.geogig.storage.BulkOpListener; import org.locationtech.geogig.storage.ObjectStore; import com.google.common.base.Preconditions; import com.google.common.base.Throwables; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.Iterables; class TreeCache { private final AtomicInteger idSequence = new AtomicInteger(); private final BiMap<Integer, ObjectId> oidMapping = HashBiMap.create(100_000); private final LoadingCache<Integer, RevTree> cache; private final ObjectStore store; public TreeCache(final ObjectStore store) { this.store = store; final CacheLoader<Integer, RevTree> loader = new CacheLoader<Integer, RevTree>() { @Override public RevTree load(Integer key) throws Exception { ObjectId treeId = oidMapping.get(key); Preconditions.checkState(treeId != null, "No tree id mapped to " + key); RevTree tree = TreeCache.this.store.getTree(treeId); return tree; } }; this.cache = CacheBuilder.newBuilder().concurrencyLevel(1).maximumSize(100_000).build(loader); } public RevTree getTree(final ObjectId treeId) { Integer internalId = oidMapping.inverse().get(treeId); final RevTree tree; if (internalId == null) { tree = store.getTree(treeId); getTreeId(tree); if (!tree.buckets().isEmpty()) { preload(Iterables.transform(tree.buckets().values(), (b) -> b.getObjectId())); } } else { tree = resolve(internalId.intValue()); } return tree; } public RevTree resolve(final int leafRevTreeId) { RevTree tree; try { tree = cache.get(Integer.valueOf(leafRevTreeId)); } catch (ExecutionException e) { throw Throwables.propagate(e); } Preconditions.checkNotNull(tree); return tree; } public Integer getTreeId(RevTree tree) { Integer cacheId = oidMapping.inverse().get(tree.getId()); if (cacheId == null) { cacheId = Integer.valueOf(idSequence.incrementAndGet()); oidMapping.put(cacheId, tree.getId()); cache.put(cacheId, tree); } return cacheId; } public void preload(Iterable<ObjectId> trees) { Iterator<RevTree> preloaded = store.getAll(trees, BulkOpListener.NOOP_LISTENER, RevTree.class); while (preloaded.hasNext()) { getTreeId(preloaded.next()); } } }