org.modeshape.jcr.index.local.LocalMapIndex Maven / Gradle / Ivy
/*
* ModeShape (http://www.modeshape.org)
*
* 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.modeshape.jcr.index.local;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.NavigableSet;
import java.util.concurrent.ConcurrentMap;
import javax.jcr.query.qom.Constraint;
import org.mapdb.BTreeKeySerializer;
import org.mapdb.BTreeMap;
import org.mapdb.Bind;
import org.mapdb.DB;
import org.mapdb.Fun;
import org.mapdb.Serializer;
import org.modeshape.common.logging.Logger;
import org.modeshape.jcr.index.local.IndexValues.Converter;
import org.modeshape.jcr.spi.index.IndexConstraints;
import org.modeshape.jcr.value.ValueComparators;
/**
* Abstract map-based index.
*
* @author Randall Hauch ([email protected])
* @param the type of value to be indexed
* @param the raw type of value to be added
*/
abstract class LocalMapIndex implements LocalIndex {
protected final Logger logger = Logger.getLogger(getClass());
protected final String name;
protected final String workspace;
protected final BTreeMap keysByValue;
protected final NavigableSet> valuesByKey;
protected final ConcurrentMap options;
private final Converter converter;
private final DB db;
protected final Comparator comparator;
private final boolean isNew;
LocalMapIndex( String name,
String workspaceName,
DB db,
Converter converter,
BTreeKeySerializer valueSerializer,
Serializer valueRawSerializer ) {
assert name != null;
assert workspaceName != null;
assert db != null;
assert converter != null;
assert valueSerializer != null;
this.name = name;
this.workspace = workspaceName;
this.converter = converter;
this.db = db;
if (db.exists(name)) {
logger.debug("Reopening storage for '{0}' index in workspace '{1}'", name, workspaceName);
this.options = db.getHashMap(name + "/options");
this.keysByValue = db.getTreeMap(name);
this.valuesByKey = db.getTreeSet(name + "/inverse");
this.isNew = false;
} else {
logger.debug("Creating storage for '{0}' index in workspace '{1}'", name, workspaceName);
this.isNew = true;
this.options = db.createHashMap(name + "/options").make();
this.keysByValue = db.createTreeMap(name).counterEnable().comparator(valueSerializer.getComparator())
.keySerializer(valueSerializer).make();
// Create the TreeSet used in the reverse mapping, but we have to set a comparator that works in terms of the
// Fun.Tuple2 ...
final Comparator strComparator = ValueComparators.STRING_COMPARATOR;
final Serializer strSerializer = Serializer.STRING;
final Comparator valueComparator = valueSerializer.getComparator();
final Comparator> revComparator = MapDB.tupleComparator(strComparator, valueComparator);
final BTreeKeySerializer> revSerializer = MapDB.tupleBTreeSerializer(strComparator,
strSerializer,
valueRawSerializer,
revComparator);
this.valuesByKey = db.createTreeSet(name + "/inverse").comparator(revComparator).serializer(revSerializer).make();
}
this.comparator = valueSerializer.getComparator();
// Bind the map and the set together so the set is auto-updated as the map is changed ...
Bind.mapInverse(this.keysByValue, this.valuesByKey);
}
@Override
public String getName() {
return name;
}
public String getWorkspaceName() {
return workspace;
}
@Override
public boolean isNew() {
return isNew;
}
@Override
public long estimateTotalCount() {
return keysByValue.sizeLong();
}
protected final Converter converter() {
return converter;
}
@Override
public Results filter( IndexConstraints filter ) {
return Operations.createFilter(keysByValue, converter, filter.getConstraints(), filter.getVariables()).getResults();
}
@Override
public long estimateCardinality( Constraint constraint,
Map variables ) {
return Operations.createFilter(keysByValue, converter, Collections.singleton(constraint), variables).estimateCount();
}
@Override
public void removeAll() {
keysByValue.clear();
}
@Override
public void commit() {
db.commit();
}
@Override
public void shutdown( boolean destroyed ) {
if (destroyed) {
// Remove the database since the index was destroyed ...
db.delete(name);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy