blob: 825bbcff7dc139f7c2a9e9626e3a99caee31c273 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.hugegraph.backend.store.memory;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.hugegraph.backend.BackendException;
import org.apache.hugegraph.backend.LocalCounter;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.query.Query;
import org.apache.hugegraph.backend.serializer.TextBackendEntry;
import org.apache.hugegraph.backend.store.AbstractBackendStore;
import org.apache.hugegraph.backend.store.BackendAction;
import org.apache.hugegraph.backend.store.BackendEntry;
import org.apache.hugegraph.backend.store.BackendFeatures;
import org.apache.hugegraph.backend.store.BackendMutation;
import org.apache.hugegraph.backend.store.BackendSession;
import org.apache.hugegraph.backend.store.BackendStoreProvider;
import org.apache.hugegraph.config.HugeConfig;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.util.Log;
import org.slf4j.Logger;
/**
* NOTE:
* InMemoryDBStore support:
* 1.query by id (include query edges by id)
* 2.query by condition (include query edges by condition)
* 3.remove by id
* 4.range query
* 5.append/subtract index data(element-id) and vertex-property
* 6.query edge by edge-label
* InMemoryDBStore not support currently:
* 1.remove by id + condition
* 2.append/subtract edge-property
*/
public abstract class InMemoryDBStore
extends AbstractBackendStore<BackendSession> {
private static final Logger LOG = Log.logger(InMemoryDBStore.class);
private final BackendStoreProvider provider;
private final String store;
private final String database;
private final Map<HugeType, InMemoryDBTable> tables;
public InMemoryDBStore(final BackendStoreProvider provider,
final String database, final String store) {
this.provider = provider;
this.database = database;
this.store = store;
this.tables = new HashMap<>();
this.registerMetaHandlers();
LOG.debug("Store loaded: {}", store);
}
private void registerMetaHandlers() {
this.registerMetaHandler("metrics", (session, meta, args) -> {
InMemoryMetrics metrics = new InMemoryMetrics();
return metrics.metrics();
});
}
protected void registerTableManager(HugeType type, InMemoryDBTable table) {
this.tables.put(type, table);
}
protected Collection<InMemoryDBTable> tables() {
return this.tables.values();
}
@Override
protected final InMemoryDBTable table(HugeType type) {
assert type != null;
InMemoryDBTable table = this.tables.get(type);
if (table == null) {
throw new BackendException("Unsupported table type: %s", type);
}
return table;
}
@Override
protected BackendSession session(HugeType type) {
return null;
}
@Override
public Iterator<BackendEntry> query(Query query) {
InMemoryDBTable table = this.table(InMemoryDBTable.tableType(query));
Iterator<BackendEntry> rs = table.query(null, query);
LOG.debug("[store {}] has result({}) for query: {}",
this.store, rs.hasNext(), query);
return rs;
}
@Override
public Number queryNumber(Query query) {
InMemoryDBTable table = this.table(InMemoryDBTable.tableType(query));
Number result = table.queryNumber(null, query);
LOG.debug("[store {}] get result({}) for number query: {}",
this.store, result, query);
return result;
}
@Override
public void mutate(BackendMutation mutation) {
for (Iterator<BackendAction> it = mutation.mutation(); it.hasNext(); ) {
this.mutate(it.next());
}
}
protected void mutate(BackendAction item) {
BackendEntry e = item.entry();
assert e instanceof TextBackendEntry;
TextBackendEntry entry = (TextBackendEntry) e;
InMemoryDBTable table = this.table(entry.type());
switch (item.action()) {
case INSERT:
LOG.debug("[store {}] add entry: {}", this.store, entry);
table.insert(null, entry);
break;
case DELETE:
LOG.debug("[store {}] remove id: {}", this.store, entry.id());
table.delete(null, entry);
break;
case APPEND:
LOG.debug("[store {}] append entry: {}", this.store, entry);
table.append(null, entry);
break;
case ELIMINATE:
LOG.debug("[store {}] eliminate entry: {}", this.store, entry);
table.eliminate(null, entry);
break;
case UPDATE_IF_PRESENT:
table.updateIfPresent(null, entry);
break;
case UPDATE_IF_ABSENT:
table.updateIfAbsent(null, entry);
break;
default:
throw new BackendException("Unsupported mutate type: %s",
item.action());
}
}
@Override
public String store() {
return this.store;
}
@Override
public String database() {
return this.database;
}
@Override
public BackendStoreProvider provider() {
return this.provider;
}
@Override
public void open(HugeConfig config) {
LOG.debug("Store opened: {}", this.store);
}
@Override
public void close() throws BackendException {
LOG.debug("Store closed: {}", this.store);
}
@Override
public void init() {
for (InMemoryDBTable table : this.tables()) {
table.init(null);
}
LOG.debug("Store initialized: {}", this.store);
}
@Override
public void clear(boolean clearSpace) {
for (InMemoryDBTable table : this.tables()) {
table.clear(null);
}
LOG.debug("Store cleared: {}", this.store);
}
@Override
public void truncate() {
for (InMemoryDBTable table : this.tables()) {
table.clear(null);
}
LOG.debug("Store truncated: {}", this.store);
}
@Override
public void beginTx() {
// pass
}
@Override
public void commitTx() {
// pass
}
@Override
public void rollbackTx() {
throw new UnsupportedOperationException(
"Unsupported rollback operation by InMemoryDBStore");
}
@Override
public BackendFeatures features() {
return FEATURES;
}
@Override
public boolean opened() {
return true;
}
@Override
public boolean initialized() {
return true;
}
/***************************** Store defines *****************************/
public static class InMemorySchemaStore extends InMemoryDBStore {
private final LocalCounter counter = new LocalCounter();
public InMemorySchemaStore(BackendStoreProvider provider,
String database, String store) {
super(provider, database, store);
registerTableManager(HugeType.VERTEX_LABEL,
new InMemoryDBTable(HugeType.VERTEX_LABEL));
registerTableManager(HugeType.EDGE_LABEL,
new InMemoryDBTable(HugeType.EDGE_LABEL));
registerTableManager(HugeType.PROPERTY_KEY,
new InMemoryDBTable(HugeType.PROPERTY_KEY));
registerTableManager(HugeType.INDEX_LABEL,
new InMemoryDBTable(HugeType.INDEX_LABEL));
registerTableManager(HugeType.SECONDARY_INDEX,
new InMemoryDBTables.SecondaryIndex());
}
@Override
public Id nextId(HugeType type) {
return this.counter.nextId(type);
}
@Override
public void increaseCounter(HugeType type, long increment) {
this.counter.increaseCounter(type, increment);
}
@Override
public long getCounter(HugeType type) {
return this.counter.getCounter(type);
}
@Override
public void clear(boolean clearSpace) {
this.counter.reset();
super.clear(clearSpace);
}
@Override
public void truncate() {
this.counter.reset();
super.truncate();
}
@Override
public boolean isSchemaStore() {
return true;
}
}
public static class InMemoryGraphStore extends InMemoryDBStore {
public InMemoryGraphStore(BackendStoreProvider provider,
String database, String store) {
super(provider, database, store);
registerTableManager(HugeType.VERTEX,
new InMemoryDBTables.Vertex());
registerTableManager(HugeType.EDGE_OUT,
new InMemoryDBTables.Edge(HugeType.EDGE_OUT));
registerTableManager(HugeType.EDGE_IN,
new InMemoryDBTables.Edge(HugeType.EDGE_IN));
registerTableManager(HugeType.SECONDARY_INDEX,
new InMemoryDBTables.SecondaryIndex());
registerTableManager(HugeType.RANGE_INT_INDEX,
InMemoryDBTables.RangeIndex.rangeInt());
registerTableManager(HugeType.RANGE_FLOAT_INDEX,
InMemoryDBTables.RangeIndex.rangeFloat());
registerTableManager(HugeType.RANGE_LONG_INDEX,
InMemoryDBTables.RangeIndex.rangeLong());
registerTableManager(HugeType.RANGE_DOUBLE_INDEX,
InMemoryDBTables.RangeIndex.rangeDouble());
registerTableManager(HugeType.SEARCH_INDEX,
new InMemoryDBTables.SearchIndex());
registerTableManager(HugeType.SHARD_INDEX,
new InMemoryDBTables.ShardIndex());
registerTableManager(HugeType.UNIQUE_INDEX,
new InMemoryDBTables.UniqueIndex());
}
@Override
public boolean isSchemaStore() {
return false;
}
@Override
public Id nextId(HugeType type) {
throw new UnsupportedOperationException(
"InMemoryGraphStore.nextId()");
}
@Override
public void increaseCounter(HugeType type, long num) {
throw new UnsupportedOperationException(
"InMemoryGraphStore.increaseCounter()");
}
@Override
public long getCounter(HugeType type) {
throw new UnsupportedOperationException(
"InMemoryGraphStore.getCounter()");
}
}
public static class InMemorySystemStore extends InMemoryGraphStore {
public InMemorySystemStore(BackendStoreProvider provider,
String database, String store) {
super(provider, database, store);
}
@Override
public String storedVersion() {
return this.provider().driverVersion();
}
}
/**
* InMemoryDBStore features
*/
private static final BackendFeatures FEATURES = new BackendFeatures() {
@Override
public boolean supportsPersistence() {
return false;
}
@Override
public boolean supportsSharedStorage() {
return false;
}
@Override
public boolean supportsScanToken() {
return false;
}
@Override
public boolean supportsScanKeyPrefix() {
return false;
}
@Override
public boolean supportsScanKeyRange() {
return false;
}
@Override
public boolean supportsQuerySchemaByName() {
// Traversal all data in memory
return true;
}
@Override
public boolean supportsQueryByLabel() {
// Traversal all data in memory
return true;
}
@Override
public boolean supportsQueryWithInCondition() {
return false;
}
@Override
public boolean supportsQueryWithRangeCondition() {
return true;
}
@Override
public boolean supportsQueryWithOrderBy() {
return false;
}
@Override
public boolean supportsQueryWithContains() {
// NOTE: hasValue tests will skip
return false;
}
@Override
public boolean supportsQueryWithContainsKey() {
// NOTE: hasKey tests will skip
return false;
}
@Override
public boolean supportsQueryByPage() {
return false;
}
@Override
public boolean supportsQuerySortByInputIds() {
return true;
}
@Override
public boolean supportsDeleteEdgeByLabel() {
return false;
}
@Override
public boolean supportsUpdateVertexProperty() {
return false;
}
@Override
public boolean supportsMergeVertexProperty() {
return false;
}
@Override
public boolean supportsUpdateEdgeProperty() {
return false;
}
@Override
public boolean supportsTransaction() {
return false;
}
@Override
public boolean supportsNumberType() {
return false;
}
@Override
public boolean supportsAggregateProperty() {
return false;
}
@Override
public boolean supportsTtl() {
return false;
}
@Override
public boolean supportsOlapProperties() {
return false;
}
};
}