// Copyright 2017 JanusGraph Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package org.janusgraph.graphdb.vertices; import org.janusgraph.diskstorage.EntryList; import org.janusgraph.diskstorage.keycolumnvalue.SliceQuery; import org.janusgraph.graphdb.transaction.StandardJanusGraphTx; import org.janusgraph.util.datastructures.Retriever; import java.util.HashMap; import java.util.Map; /** * @author Matthias Broecheler (me@matthiasb.com) */ public class CacheVertex extends StandardVertex { // We don't try to be smart and match with previous queries // because that would waste more cycles on lookup than save actual memory // We use a normal map with synchronization since the likelihood of contention // is super low in a single transaction protected final Map<SliceQuery, EntryList> queryCache; public CacheVertex(StandardJanusGraphTx tx, long id, byte lifecycle) { super(tx, id, lifecycle); queryCache = new HashMap<SliceQuery, EntryList>(4); } protected void addToQueryCache(final SliceQuery query, final EntryList entries) { synchronized (queryCache) { //TODO: become smarter about what to cache and when (e.g. memory pressure) queryCache.put(query, entries); } } protected int getQueryCacheSize() { synchronized (queryCache) { return queryCache.size(); } } @Override public EntryList loadRelations(final SliceQuery query, final Retriever<SliceQuery, EntryList> lookup) { if (isNew()) return EntryList.EMPTY_LIST; EntryList result; synchronized (queryCache) { result = queryCache.get(query); } if (result == null) { //First check for super Map.Entry<SliceQuery, EntryList> superset = getSuperResultSet(query); if (superset == null) { result = lookup.get(query); } else { result = query.getSubset(superset.getKey(), superset.getValue()); } addToQueryCache(query, result); } return result; } @Override public boolean hasLoadedRelations(final SliceQuery query) { synchronized (queryCache) { return queryCache.get(query) != null || getSuperResultSet(query) != null; } } private Map.Entry<SliceQuery, EntryList> getSuperResultSet(final SliceQuery query) { synchronized (queryCache) { if (queryCache.size() > 0) { for (Map.Entry<SliceQuery, EntryList> entry : queryCache.entrySet()) { if (entry.getKey().subsumes(query)) return entry; } } } return null; } }