/* * Copyright (C) 2014 Indeed Inc. * * 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 com.indeed.flamdex; import com.google.common.base.Throwables; import com.google.common.collect.Maps; import com.indeed.flamdex.api.FlamdexOutOfMemoryException; import com.indeed.flamdex.api.FlamdexReader; import com.indeed.flamdex.api.GenericIntTermDocIterator; import com.indeed.flamdex.api.GenericStringTermDocIterator; import com.indeed.flamdex.api.IntTermDocIterator; import com.indeed.flamdex.api.IntValueLookup; import com.indeed.flamdex.api.StringTermDocIterator; import com.indeed.flamdex.api.StringValueLookup; import com.indeed.flamdex.fieldcache.FieldCacher; import com.indeed.flamdex.fieldcache.UnsortedIntTermDocIterator; import com.indeed.flamdex.fieldcache.UnsortedIntTermDocIteratorImpl; import java.io.IOException; import java.util.Map; /** * @author jsgroth * * FlamdexReader base class that provides implementations of some of the {@link FlamdexReader} methods * * at the moment of this comment's writing, {@link FlamdexReader#getMetric} and {@link FlamdexReader#memoryRequired} are implemented here */ public abstract class AbstractFlamdexReader implements FlamdexReader { protected final String directory; protected final int numDocs; private final boolean useMMapMetrics; private final Map<String, FieldCacher> intFieldCachers; protected AbstractFlamdexReader(String directory, int numDocs) { this(directory, numDocs, System.getProperty("flamdex.mmap.fieldcache") != null); } protected AbstractFlamdexReader(String directory, int numDocs, boolean useMMapMetrics) { this.directory = directory; this.numDocs = numDocs; this.useMMapMetrics = useMMapMetrics; this.intFieldCachers = Maps.newHashMap(); } // this implementation will be correct for any FlamdexReader, but // subclasses may want to override for efficiency reasons protected UnsortedIntTermDocIterator createUnsortedIntTermDocIterator(String field) { return UnsortedIntTermDocIteratorImpl.create(this, field); } @Override public final IntValueLookup getMetric(String metric) throws FlamdexOutOfMemoryException { final FieldCacher fieldCacher = getMetricCacher(metric); final UnsortedIntTermDocIterator iterator = createUnsortedIntTermDocIterator(metric); try { return cacheField(iterator, metric, fieldCacher); } finally { iterator.close(); } } public StringValueLookup getStringLookup(final String field) throws FlamdexOutOfMemoryException { try { return FieldCacher.newStringValueLookup(field, this, directory); } catch (IOException e) { throw Throwables.propagate(e); } } private IntValueLookup cacheField(UnsortedIntTermDocIterator iterator, String metric, FieldCacher fieldCacher) { if (useMMapMetrics) { try { return fieldCacher.newMMapFieldCache(iterator, numDocs, metric, directory); } catch (IOException e) { throw new RuntimeException(e); } } return fieldCacher.newFieldCache(iterator, numDocs); } @Override public final long memoryRequired(String metric) { if (useMMapMetrics) return 0; final FieldCacher fieldCacher = getMetricCacher(metric); return fieldCacher.memoryRequired(numDocs); } private FieldCacher getMetricCacher(String metric) { synchronized (intFieldCachers) { if (!intFieldCachers.containsKey(metric)) { final FieldCacher cacher = FieldCacher.getCacherForField(metric, this); intFieldCachers.put(metric, cacher); } return intFieldCachers.get(metric); } } @Override public IntTermDocIterator getIntTermDocIterator(final String field) { return new GenericIntTermDocIterator(getIntTermIterator(field), getDocIdStream()); } @Override public StringTermDocIterator getStringTermDocIterator(final String field) { return new GenericStringTermDocIterator(getStringTermIterator(field), getDocIdStream()); } @Override public int getNumDocs() { return numDocs; } @Override public String getDirectory() { return directory; } }