From efcd839ee2222b01fdbf87b64ba39711fa038310 Mon Sep 17 00:00:00 2001 From: Jermy Li Date: Tue, 17 Sep 2019 11:14:30 +0800 Subject: [PATCH] support bin serialization for cassandra (#680) Change-Id: Ib4f48f3235ac9e5526c63c5617e3819ab4d29711 --- .../cassandra/CassandraBackendEntry.java | 40 ---- .../store/cassandra/CassandraSerializer.java | 56 ++++- .../cassandra/CassandraStoreProvider.java | 3 +- .../store/cassandra/CassandraTable.java | 2 + .../store/cassandra/CassandraTables.java | 176 ++++++-------- .../baidu/hugegraph/backend/id/EdgeId.java | 12 + .../com/baidu/hugegraph/backend/id/Id.java | 4 + .../hugegraph/backend/id/IdGenerator.java | 98 ++++++-- .../baidu/hugegraph/backend/id/IdUtil.java | 33 ++- .../backend/id/SnowflakeIdGenerator.java | 2 +- .../serializer/BinaryBackendEntry.java | 4 +- .../serializer/BinaryInlineSerializer.java | 13 +- .../backend/serializer/BinarySerializer.java | 35 +-- .../backend/serializer/BytesBuffer.java | 108 ++++++--- .../backend/serializer/SerializerFactory.java | 8 +- .../backend/serializer/TableBackendEntry.java | 28 ++- .../backend/serializer/TableSerializer.java | 111 +++++---- .../com/baidu/hugegraph/type/HugeType.java | 4 + .../baidu/hugegraph/type/define/DataType.java | 10 + .../store/hbase/HbaseStoreProvider.java | 3 +- .../store/mysql/MysqlBackendEntry.java | 40 ---- .../backend/store/mysql/MysqlSerializer.java | 9 +- .../store/mysql/MysqlStoreProvider.java | 3 +- .../backend/store/mysql/MysqlTable.java | 58 ++--- .../backend/store/mysql/MysqlTables.java | 8 +- .../backend/store/mysql/MysqlUtil.java | 71 +++--- .../backend/store/mysql/WhereBuilder.java | 139 +++++++---- .../backend/store/palo/PaloStoreProvider.java | 3 +- .../postgresql/PostgresqlSerializer.java | 8 - .../store/postgresql/PostgresqlSessions.java | 6 +- .../postgresql/PostgresqlStoreProvider.java | 3 +- .../store/postgresql/PostgresqlTable.java | 26 ++- .../store/rocksdb/RocksDBStoreProvider.java | 3 +- .../hugegraph/core/EdgeLabelCoreTest.java | 220 ++++++++++-------- .../hugegraph/core/VertexLabelCoreTest.java | 120 ++++++---- .../baidu/hugegraph/testutil/FakeObjects.java | 2 +- .../com/baidu/hugegraph/unit/FakeObjects.java | 57 +++++ .../baidu/hugegraph/unit/UnitTestSuite.java | 32 ++- .../{core => cassandra}/CassandraTest.java | 2 +- .../unit/core/SecurityManagerTest.java | 4 +- .../hugegraph/unit/{core => id}/IdTest.java | 90 +++++-- .../unit/{util => id}/IdUtilTest.java | 43 +++- .../hugegraph/unit/mysql/MysqlUtilTest.java | 62 +++++ .../unit/mysql/WhereBuilderTest.java | 125 ++++++++++ .../serializer/BinaryBackendEntryTest.java | 115 +++++++++ .../BinaryInlineSerializerTest.java | 82 +++++++ .../{core => serializer}/BytesBufferTest.java | 2 +- .../serializer/SerializerFactoryTest.java | 90 +++++++ .../serializer/TableBackendEntryTest.java | 194 +++++++++++++++ .../unit/serializer/TextBackendEntryTest.java | 96 ++++++++ .../hugegraph/unit/util/JsonUtilTest.java | 14 +- 51 files changed, 1803 insertions(+), 674 deletions(-) rename hugegraph-test/src/main/java/com/baidu/hugegraph/unit/{core => cassandra}/CassandraTest.java (99%) rename hugegraph-test/src/main/java/com/baidu/hugegraph/unit/{core => id}/IdTest.java (68%) rename hugegraph-test/src/main/java/com/baidu/hugegraph/unit/{util => id}/IdUtilTest.java (72%) create mode 100644 hugegraph-test/src/main/java/com/baidu/hugegraph/unit/mysql/MysqlUtilTest.java create mode 100644 hugegraph-test/src/main/java/com/baidu/hugegraph/unit/mysql/WhereBuilderTest.java create mode 100644 hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/BinaryBackendEntryTest.java create mode 100644 hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/BinaryInlineSerializerTest.java rename hugegraph-test/src/main/java/com/baidu/hugegraph/unit/{core => serializer}/BytesBufferTest.java (99%) create mode 100644 hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/SerializerFactoryTest.java create mode 100644 hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/TableBackendEntryTest.java create mode 100644 hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/TextBackendEntryTest.java diff --git a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraBackendEntry.java b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraBackendEntry.java index 654aea845..8607737e7 100644 --- a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraBackendEntry.java +++ b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraBackendEntry.java @@ -19,11 +19,8 @@ package com.baidu.hugegraph.backend.store.cassandra; -import java.util.Collection; - import com.baidu.hugegraph.backend.id.Id; import com.baidu.hugegraph.backend.serializer.TableBackendEntry; -import com.baidu.hugegraph.backend.store.BackendEntry; import com.baidu.hugegraph.type.HugeType; public class CassandraBackendEntry extends TableBackendEntry { @@ -43,41 +40,4 @@ public class CassandraBackendEntry extends TableBackendEntry { public CassandraBackendEntry(TableBackendEntry.Row row) { super(row); } - - @Override - public String toString() { - return String.format("CassandraBackendEntry{%s, sub-rows: %s}", - this.row().toString(), - this.subRows().toString()); - } - - @Override - public int columnsSize() { - throw new RuntimeException("Not supported by Cassandra"); - } - - @Override - public Collection columns() { - throw new RuntimeException("Not supported by Cassandra"); - } - - @Override - public void columns(Collection bytesColumns) { - throw new RuntimeException("Not supported by Cassandra"); - } - - @Override - public void columns(BackendColumn... bytesColumns) { - throw new RuntimeException("Not supported by Cassandra"); - } - - @Override - public void merge(BackendEntry other) { - throw new RuntimeException("Not supported by Cassandra"); - } - - @Override - public void clear() { - throw new RuntimeException("Not supported by Cassandra"); - } } diff --git a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraSerializer.java b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraSerializer.java index 628e965ea..4c8accbea 100644 --- a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraSerializer.java +++ b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraSerializer.java @@ -19,6 +19,7 @@ package com.baidu.hugegraph.backend.store.cassandra; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -28,13 +29,17 @@ import java.util.Set; import com.baidu.hugegraph.backend.BackendException; import com.baidu.hugegraph.backend.id.Id; import com.baidu.hugegraph.backend.id.IdGenerator; +import com.baidu.hugegraph.backend.id.IdUtil; +import com.baidu.hugegraph.backend.serializer.BytesBuffer; import com.baidu.hugegraph.backend.serializer.TableBackendEntry; import com.baidu.hugegraph.backend.serializer.TableSerializer; import com.baidu.hugegraph.backend.store.BackendEntry; +import com.baidu.hugegraph.schema.PropertyKey; import com.baidu.hugegraph.schema.SchemaElement; import com.baidu.hugegraph.structure.HugeElement; import com.baidu.hugegraph.structure.HugeProperty; import com.baidu.hugegraph.type.HugeType; +import com.baidu.hugegraph.type.define.DataType; import com.baidu.hugegraph.type.define.HugeKeys; import com.baidu.hugegraph.util.InsertionOrderUtil; import com.baidu.hugegraph.util.JsonUtil; @@ -62,7 +67,7 @@ public class CassandraSerializer extends TableSerializer { } @Override - protected Set parseIndexElemIds(TableBackendEntry entry) { + protected Set parseIndexElemIds(TableBackendEntry entry) { return ImmutableSet.of(entry.column(HugeKeys.ELEMENT_IDS)); } @@ -110,9 +115,7 @@ public class CassandraSerializer extends TableSerializer { } else { // Format properties for (HugeProperty prop : element.getProperties().values()) { - row.column(HugeKeys.PROPERTIES, - prop.propertyKey().id().asLong(), - JsonUtil.toJson(prop.value())); + this.formatProperty(prop, row); } } } @@ -120,13 +123,52 @@ public class CassandraSerializer extends TableSerializer { @Override protected void parseProperties(HugeElement element, TableBackendEntry.Row row) { - Map props = row.column(HugeKeys.PROPERTIES); - for (Map.Entry prop : props.entrySet()) { - Id pkeyId = toId(prop.getKey()); + Map props = row.column(HugeKeys.PROPERTIES); + for (Map.Entry prop : props.entrySet()) { + Id pkeyId = this.toId(prop.getKey()); this.parseProperty(pkeyId, prop.getValue(), element); } } + @Override + protected Object writeProperty(HugeProperty property) { + BytesBuffer buffer = BytesBuffer.allocate(BytesBuffer.BUF_PROPERTY); + buffer.writeProperty(property.propertyKey(), property.value()); + buffer.flip(); + return buffer.asByteBuffer(); + } + + @Override + protected Object writeProperty(Object value) { + /* + * Since we can't know the type of the property value in some scenarios, + * so need to construct a fake property key to serialize to reuse code. + */ + PropertyKey pkey = new PropertyKey(null, IdGenerator.of(0L), "fake"); + pkey.dataType(DataType.fromClass(value.getClass())); + BytesBuffer buffer = BytesBuffer.allocate(BytesBuffer.BUF_PROPERTY); + buffer.writeProperty(pkey, value); + buffer.flip(); + return buffer.asByteBuffer(); + } + + @Override + @SuppressWarnings("unchecked") + protected T readProperty(PropertyKey pkey, Object value) { + BytesBuffer buffer = BytesBuffer.wrap((ByteBuffer) value); + return (T) buffer.readProperty(pkey); + } + + @Override + protected Object writeId(Id id) { + return IdUtil.writeBinString(id); + } + + @Override + protected Id readId(Object id) { + return IdUtil.readBinString(id); + } + @Override protected void writeUserdata(SchemaElement schema, TableBackendEntry entry) { diff --git a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraStoreProvider.java b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraStoreProvider.java index a5f100226..636240be3 100644 --- a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraStoreProvider.java +++ b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraStoreProvider.java @@ -57,7 +57,8 @@ public class CassandraStoreProvider extends AbstractBackendStoreProvider { * also split range table to rangeInt, rangeFloat, * rangeLong and rangeDouble * [1.5] #633: support unique index + * [1.6] #661 & #680: support bin serialization for cassandra */ - return "1.5"; + return "1.6"; } } diff --git a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraTable.java b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraTable.java index 66a0c4cf5..f838c6614 100644 --- a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraTable.java +++ b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraTable.java @@ -108,6 +108,8 @@ public abstract class CassandraTable rs.extend(this.results2Entries(query, results)); } } catch (DriverException e) { + LOG.debug("Failed to query [{}], detail statement: {}", + query, selections, e); throw new BackendException("Failed to query [%s]", e, query); } diff --git a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraTables.java b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraTables.java index fd1e4210f..8d704a97c 100644 --- a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraTables.java +++ b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraTables.java @@ -52,12 +52,15 @@ public class CassandraTables { public static final String LABEL_INDEX = "label_index"; public static final String NAME_INDEX = "name_index"; - private static final DataType DATATYPE_PK = DataType.cint(); - private static final DataType DATATYPE_SL = DataType.cint(); // VL/EL - private static final DataType DATATYPE_IL = DataType.cint(); + private static final DataType TYPE_PK = DataType.cint(); + private static final DataType TYPE_SL = DataType.cint(); // VL/EL + private static final DataType TYPE_IL = DataType.cint(); - private static final DataType DATATYPE_UD = DataType.map(DataType.text(), - DataType.text()); + private static final DataType TYPE_UD = DataType.map(DataType.text(), + DataType.text()); + + private static final DataType TYPE_ID = DataType.blob(); + private static final DataType TYPE_PROP = DataType.blob(); private static final int COMMIT_DELETE_BATCH = 1000; @@ -116,19 +119,19 @@ public class CassandraTables { @Override public void init(CassandraSessionPool.Session session) { ImmutableMap pkeys = ImmutableMap.of( - HugeKeys.ID, DATATYPE_SL + HugeKeys.ID, TYPE_SL ); ImmutableMap ckeys = ImmutableMap.of(); ImmutableMap columns = ImmutableMap .builder() .put(HugeKeys.NAME, DataType.text()) .put(HugeKeys.ID_STRATEGY, DataType.tinyint()) - .put(HugeKeys.PRIMARY_KEYS, DataType.list(DATATYPE_PK)) - .put(HugeKeys.NULLABLE_KEYS, DataType.set(DATATYPE_PK)) - .put(HugeKeys.INDEX_LABELS, DataType.set(DATATYPE_IL)) - .put(HugeKeys.PROPERTIES, DataType.set(DATATYPE_PK)) + .put(HugeKeys.PRIMARY_KEYS, DataType.list(TYPE_PK)) + .put(HugeKeys.NULLABLE_KEYS, DataType.set(TYPE_PK)) + .put(HugeKeys.INDEX_LABELS, DataType.set(TYPE_IL)) + .put(HugeKeys.PROPERTIES, DataType.set(TYPE_PK)) .put(HugeKeys.ENABLE_LABEL_INDEX, DataType.cboolean()) - .put(HugeKeys.USER_DATA, DATATYPE_UD) + .put(HugeKeys.USER_DATA, TYPE_UD) .put(HugeKeys.STATUS, DataType.tinyint()) .build(); @@ -148,21 +151,21 @@ public class CassandraTables { @Override public void init(CassandraSessionPool.Session session) { ImmutableMap pkeys = ImmutableMap.of( - HugeKeys.ID, DATATYPE_SL + HugeKeys.ID, TYPE_SL ); ImmutableMap ckeys = ImmutableMap.of(); ImmutableMap columns = ImmutableMap .builder() .put(HugeKeys.NAME, DataType.text()) .put(HugeKeys.FREQUENCY, DataType.tinyint()) - .put(HugeKeys.SOURCE_LABEL, DATATYPE_SL) - .put(HugeKeys.TARGET_LABEL, DATATYPE_SL) - .put(HugeKeys.SORT_KEYS, DataType.list(DATATYPE_PK)) - .put(HugeKeys.NULLABLE_KEYS, DataType.set(DATATYPE_PK)) - .put(HugeKeys.INDEX_LABELS, DataType.set(DATATYPE_IL)) - .put(HugeKeys.PROPERTIES, DataType.set(DATATYPE_PK)) + .put(HugeKeys.SOURCE_LABEL, TYPE_SL) + .put(HugeKeys.TARGET_LABEL, TYPE_SL) + .put(HugeKeys.SORT_KEYS, DataType.list(TYPE_PK)) + .put(HugeKeys.NULLABLE_KEYS, DataType.set(TYPE_PK)) + .put(HugeKeys.INDEX_LABELS, DataType.set(TYPE_IL)) + .put(HugeKeys.PROPERTIES, DataType.set(TYPE_PK)) .put(HugeKeys.ENABLE_LABEL_INDEX, DataType.cboolean()) - .put(HugeKeys.USER_DATA, DATATYPE_UD) + .put(HugeKeys.USER_DATA, TYPE_UD) .put(HugeKeys.STATUS, DataType.tinyint()) .build(); @@ -190,8 +193,8 @@ public class CassandraTables { .put(HugeKeys.NAME, DataType.text()) .put(HugeKeys.DATA_TYPE, DataType.tinyint()) .put(HugeKeys.CARDINALITY, DataType.tinyint()) - .put(HugeKeys.PROPERTIES, DataType.set(DATATYPE_PK)) - .put(HugeKeys.USER_DATA, DATATYPE_UD) + .put(HugeKeys.PROPERTIES, DataType.set(TYPE_PK)) + .put(HugeKeys.USER_DATA, TYPE_UD) .put(HugeKeys.STATUS, DataType.tinyint()) .build(); @@ -211,16 +214,16 @@ public class CassandraTables { @Override public void init(CassandraSessionPool.Session session) { ImmutableMap pkeys = ImmutableMap.of( - HugeKeys.ID, DATATYPE_IL + HugeKeys.ID, TYPE_IL ); ImmutableMap ckeys = ImmutableMap.of(); ImmutableMap columns = ImmutableMap .builder() .put(HugeKeys.NAME, DataType.text()) .put(HugeKeys.BASE_TYPE, DataType.tinyint()) - .put(HugeKeys.BASE_VALUE, DATATYPE_SL) + .put(HugeKeys.BASE_VALUE, TYPE_SL) .put(HugeKeys.INDEX_TYPE, DataType.tinyint()) - .put(HugeKeys.FIELDS, DataType.list(DATATYPE_PK)) + .put(HugeKeys.FIELDS, DataType.list(TYPE_PK)) .put(HugeKeys.STATUS, DataType.tinyint()) .build(); @@ -240,13 +243,12 @@ public class CassandraTables { @Override public void init(CassandraSessionPool.Session session) { ImmutableMap pkeys = ImmutableMap.of( - HugeKeys.ID, DataType.text() + HugeKeys.ID, TYPE_ID ); ImmutableMap ckeys = ImmutableMap.of(); ImmutableMap columns = ImmutableMap.of( - HugeKeys.LABEL, DATATYPE_SL, - HugeKeys.PROPERTIES, DataType.map(DATATYPE_PK, - DataType.text()) + HugeKeys.LABEL, TYPE_SL, + HugeKeys.PROPERTIES, DataType.map(TYPE_PK, TYPE_PROP) ); this.createTable(session, pkeys, ckeys, columns); @@ -304,17 +306,16 @@ public class CassandraTables { @Override public void init(CassandraSessionPool.Session session) { ImmutableMap pkeys = ImmutableMap.of( - HugeKeys.OWNER_VERTEX, DataType.text() + HugeKeys.OWNER_VERTEX, TYPE_ID ); ImmutableMap ckeys = ImmutableMap.of( HugeKeys.DIRECTION, DataType.tinyint(), - HugeKeys.LABEL, DATATYPE_SL, + HugeKeys.LABEL, TYPE_SL, HugeKeys.SORT_VALUES, DataType.text(), - HugeKeys.OTHER_VERTEX, DataType.text() + HugeKeys.OTHER_VERTEX, TYPE_ID ); ImmutableMap columns = ImmutableMap.of( - HugeKeys.PROPERTIES, DataType.map(DATATYPE_PK, - DataType.text()) + HugeKeys.PROPERTIES, DataType.map(TYPE_PK, TYPE_PROP) ); this.createTable(session, pkeys, ckeys, columns); @@ -341,7 +342,9 @@ public class CassandraTables { @Override protected List idColumnValue(Id id) { EdgeId edgeId; - if (!(id instanceof EdgeId)) { + if (id instanceof EdgeId) { + edgeId = (EdgeId) id; + } else { String[] idParts = EdgeId.split(id); if (idParts.length == 1) { // Delete edge by label @@ -349,8 +352,6 @@ public class CassandraTables { } id = IdUtil.readString(id.asString()); edgeId = EdgeId.parse(id.asString()); - } else { - edgeId = (EdgeId) id; } E.checkState(edgeId.direction() == this.direction, @@ -361,12 +362,13 @@ public class CassandraTables { } protected final List idColumnValue(EdgeId edgeId) { + // TODO: move to Serializer List list = new ArrayList<>(5); - list.add(IdUtil.writeStoredString(edgeId.ownerVertexId())); - list.add(edgeId.direction().code()); + list.add(IdUtil.writeBinString(edgeId.ownerVertexId())); + list.add(edgeId.directionCode()); list.add(edgeId.edgeLabelId().asLong()); list.add(edgeId.sortValues()); - list.add(IdUtil.writeStoredString(edgeId.otherVertexId())); + list.add(IdUtil.writeBinString(edgeId.otherVertexId())); return list; } @@ -417,11 +419,11 @@ public class CassandraTables { for (Iterator it = rs.iterator(); it.hasNext();) { Row row = it.next(); // Delete OUT edges from edges_out table - String ownerVertex = row.get(OWNER_VERTEX, String.class); + Object ownerVertex = row.getObject(OWNER_VERTEX); session.add(buildDelete(label, ownerVertex, Directions.OUT)); // Delete IN edges from edges_in table - String otherVertex = row.get(OTHER_VERTEX, String.class); + Object otherVertex = row.getObject(OTHER_VERTEX); session.add(buildDelete(label, otherVertex, Directions.IN)); count += 2; @@ -432,11 +434,12 @@ public class CassandraTables { } } - private Delete buildDelete(Id label, String ownerVertex, + private Delete buildDelete(Id label, Object ownerVertex, Directions direction) { Delete delete = QueryBuilder.delete().from(edgesTable(direction)); delete.where(formatEQ(HugeKeys.OWNER_VERTEX, ownerVertex)); - delete.where(formatEQ(HugeKeys.DIRECTION, direction.code())); + delete.where(formatEQ(HugeKeys.DIRECTION, + EdgeId.directionToCode(direction))); delete.where(formatEQ(HugeKeys.LABEL, label.asLong())); return delete; } @@ -455,9 +458,8 @@ public class CassandraTables { "The next entry must be EDGE"); if (current != null) { - Id nextVertexId = IdGenerator.of( - next.column(HugeKeys.OWNER_VERTEX)); - if (current.id().equals(nextVertexId)) { + Object nextVertexId = next.column(HugeKeys.OWNER_VERTEX); + if (current.id().equals(IdGenerator.of(nextVertexId))) { current.subRow(next.row()); return current; } @@ -468,7 +470,7 @@ public class CassandraTables { private CassandraBackendEntry wrapByVertex(CassandraBackendEntry edge) { assert edge.type().isEdge(); - String ownerVertex = edge.column(HugeKeys.OWNER_VERTEX); + Object ownerVertex = edge.column(HugeKeys.OWNER_VERTEX); E.checkState(ownerVertex != null, "Invalid backend entry"); Id vertexId = IdGenerator.of(ownerVertex); CassandraBackendEntry vertex = new CassandraBackendEntry( @@ -513,8 +515,8 @@ public class CassandraTables { HugeKeys.FIELD_VALUES, DataType.text() ); ImmutableMap ckeys = ImmutableMap.of( - HugeKeys.INDEX_LABEL_ID, DATATYPE_IL, - HugeKeys.ELEMENT_IDS, DataType.text() + HugeKeys.INDEX_LABEL_ID, TYPE_IL, + HugeKeys.ELEMENT_IDS, TYPE_ID ); ImmutableMap columns = ImmutableMap.of(); @@ -643,17 +645,21 @@ public class CassandraTables { @Override public void init(CassandraSessionPool.Session session) { ImmutableMap pkeys = ImmutableMap.of( - HugeKeys.INDEX_LABEL_ID, DATATYPE_IL + HugeKeys.INDEX_LABEL_ID, TYPE_IL ); ImmutableMap ckeys = ImmutableMap.of( - HugeKeys.FIELD_VALUES, DataType.decimal(), - HugeKeys.ELEMENT_IDS, DataType.text() + HugeKeys.FIELD_VALUES, this.fieldValuesType(), + HugeKeys.ELEMENT_IDS, TYPE_ID ); ImmutableMap columns = ImmutableMap.of(); this.createTable(session, pkeys, ckeys, columns); } + protected DataType fieldValuesType() { + return DataType.decimal(); + } + @Override protected List idColumnName() { return ImmutableList.of(HugeKeys.INDEX_LABEL_ID, @@ -717,17 +723,8 @@ public class CassandraTables { } @Override - public void init(CassandraSessionPool.Session session) { - ImmutableMap pkeys = ImmutableMap.of( - HugeKeys.INDEX_LABEL_ID, DATATYPE_IL - ); - ImmutableMap ckeys = ImmutableMap.of( - HugeKeys.FIELD_VALUES, DataType.cint(), - HugeKeys.ELEMENT_IDS, DataType.text() - ); - ImmutableMap columns = ImmutableMap.of(); - - this.createTable(session, pkeys, ckeys, columns); + protected DataType fieldValuesType() { + return DataType.cint(); } } @@ -740,17 +737,8 @@ public class CassandraTables { } @Override - public void init(CassandraSessionPool.Session session) { - ImmutableMap pkeys = ImmutableMap.of( - HugeKeys.INDEX_LABEL_ID, DATATYPE_IL - ); - ImmutableMap ckeys = ImmutableMap.of( - HugeKeys.FIELD_VALUES, DataType.cfloat(), - HugeKeys.ELEMENT_IDS, DataType.text() - ); - ImmutableMap columns = ImmutableMap.of(); - - this.createTable(session, pkeys, ckeys, columns); + protected DataType fieldValuesType() { + return DataType.cfloat(); } } @@ -763,17 +751,9 @@ public class CassandraTables { } @Override - public void init(CassandraSessionPool.Session session) { - ImmutableMap pkeys = ImmutableMap.of( - HugeKeys.INDEX_LABEL_ID, DATATYPE_IL - ); - ImmutableMap ckeys = ImmutableMap.of( - HugeKeys.FIELD_VALUES, DataType.bigint(), - HugeKeys.ELEMENT_IDS, DataType.text() - ); - ImmutableMap columns = ImmutableMap.of(); - - this.createTable(session, pkeys, ckeys, columns); + protected DataType fieldValuesType() { + // TODO: DataType.varint() + return DataType.bigint(); } } @@ -786,17 +766,8 @@ public class CassandraTables { } @Override - public void init(CassandraSessionPool.Session session) { - ImmutableMap pkeys = ImmutableMap.of( - HugeKeys.INDEX_LABEL_ID, DATATYPE_IL - ); - ImmutableMap ckeys = ImmutableMap.of( - HugeKeys.FIELD_VALUES, DataType.cdouble(), - HugeKeys.ELEMENT_IDS, DataType.text() - ); - ImmutableMap columns = ImmutableMap.of(); - - this.createTable(session, pkeys, ckeys, columns); + protected DataType fieldValuesType() { + return DataType.cdouble(); } } @@ -809,17 +780,8 @@ public class CassandraTables { } @Override - public void init(CassandraSessionPool.Session session) { - ImmutableMap pkeys = ImmutableMap.of( - HugeKeys.INDEX_LABEL_ID, DATATYPE_IL - ); - ImmutableMap ckeys = ImmutableMap.of( - HugeKeys.FIELD_VALUES, DataType.text(), - HugeKeys.ELEMENT_IDS, DataType.text() - ); - ImmutableMap columns = ImmutableMap.of(); - - this.createTable(session, pkeys, ckeys, columns); + protected DataType fieldValuesType() { + return DataType.text(); } @Override diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/EdgeId.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/EdgeId.java index 1e8cfe243..7ceb89b13 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/EdgeId.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/EdgeId.java @@ -111,6 +111,10 @@ public class EdgeId implements Id { return this.direction; } + public byte directionCode() { + return directionToCode(this.direction); + } + public String sortValues() { return this.sortValues; } @@ -190,6 +194,14 @@ public class EdgeId implements Id { return this.asString(); } + public static byte directionToCode(Directions direction) { + return direction.type().code(); + } + + public static Directions directionFromCode(byte code) { + return Directions.convert(HugeType.fromCode(code)); + } + public static EdgeId parse(String id) throws NotFoundException { String[] idParts = split(id); if (!(idParts.length == 4 || idParts.length == 5)) { diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/Id.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/Id.java index f7627bae5..78afad482 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/Id.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/Id.java @@ -49,6 +49,10 @@ public interface Id extends Comparable { return this.type() == IdType.STRING; } + public default boolean edge() { + return this.type() == IdType.EDGE; + } + public enum IdType { UNKNOWN, diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/IdGenerator.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/IdGenerator.java index 850086372..1f8ae4903 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/IdGenerator.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/IdGenerator.java @@ -20,6 +20,7 @@ package com.baidu.hugegraph.backend.id; import java.util.Base64; +import java.util.Objects; import java.util.UUID; import com.baidu.hugegraph.backend.id.Id.IdType; @@ -51,6 +52,19 @@ public abstract class IdGenerator { return new LongId(id); } + public static Id of(Object id) { + if (id instanceof Id) { + return (Id) id; + } else if (id instanceof String) { + return of((String) id); + } else if (id instanceof Number) { + return of(((Number) id).longValue()); + } else if (id instanceof UUID) { + return of((UUID) id); + } + return new ObjectId(id); + } + public final static Id of(byte[] bytes, IdType type) { switch (type) { case LONG: @@ -91,24 +105,6 @@ public abstract class IdGenerator { } } - /** - * Generate a string id - * @param id original string id value - * @return wrapped id object - */ - public final Id generate(String id) { - return of(id); - } - - /** - * Generate a long id - * @param id original long id value - * @return wrapped id object - */ - public final Id generate(long id) { - return of(id); - } - /****************************** id defines ******************************/ public static final class StringId implements Id { @@ -364,4 +360,70 @@ public abstract class IdGenerator { return this.uuid.toString(); } } + + /** + * This class is just used by backend store for wrapper object as Id + */ + private static final class ObjectId implements Id { + + private final Object object; + + public ObjectId(Object object) { + E.checkNotNull(object, "object"); + this.object = object; + } + + @Override + public IdType type() { + return IdType.UNKNOWN; + } + + @Override + public Object asObject() { + return this.object; + } + + @Override + public String asString() { + throw new UnsupportedOperationException(); + } + + @Override + public long asLong() { + throw new UnsupportedOperationException(); + } + + @Override + public byte[] asBytes() { + throw new UnsupportedOperationException(); + } + + @Override + public int length() { + throw new UnsupportedOperationException(); + } + + @Override + public int compareTo(Id o) { + throw new UnsupportedOperationException(); + } + + @Override + public int hashCode() { + return this.object.hashCode(); + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof ObjectId)) { + return false; + } + return Objects.equals(this.object, ((ObjectId) other).object); + } + + @Override + public String toString() { + return this.object.toString(); + } + } } diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/IdUtil.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/IdUtil.java index 788d759d4..6cc7bf6ab 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/IdUtil.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/IdUtil.java @@ -19,9 +19,12 @@ package com.baidu.hugegraph.backend.id; +import java.nio.ByteBuffer; + import org.apache.commons.lang3.StringUtils; import com.baidu.hugegraph.backend.id.Id.IdType; +import com.baidu.hugegraph.backend.serializer.BytesBuffer; public final class IdUtil { @@ -44,36 +47,48 @@ public final class IdUtil { public static Id readStoredString(String id) { IdType type = IdType.valueOfPrefix(id); - id = id.substring(1); + String idContent = id.substring(1); switch (type) { case LONG: case STRING: case UUID: - return IdGenerator.ofStoredString(id, type); + return IdGenerator.ofStoredString(idContent, type); case EDGE: - return EdgeId.parseStoredString(id); + return EdgeId.parseStoredString(idContent); default: - throw new AssertionError("Invalid id type " + type); + throw new IllegalArgumentException("Invalid id: " + id); } } + public static Object writeBinString(Id id) { + int len = id.edge() ? BytesBuffer.BUF_EDGE_ID : id.length() + 1; + BytesBuffer buffer = BytesBuffer.allocate(len).writeId(id); + buffer.flip(); + return buffer.asByteBuffer(); + } + + public static Id readBinString(Object id) { + BytesBuffer buffer = BytesBuffer.wrap((ByteBuffer) id); + return buffer.readId(); + } + public static String writeString(Id id) { return "" + id.type().prefix() + id.asObject(); } public static Id readString(String id) { IdType type = IdType.valueOfPrefix(id); - id = id.substring(1); + String idContent = id.substring(1); switch (type) { case LONG: - return IdGenerator.of(Long.parseLong(id)); + return IdGenerator.of(Long.parseLong(idContent)); case STRING: case UUID: - return IdGenerator.of(id, type == IdType.UUID); + return IdGenerator.of(idContent, type == IdType.UUID); case EDGE: - return EdgeId.parse(id); + return EdgeId.parse(idContent); default: - throw new AssertionError("Invalid id type " + type); + throw new IllegalArgumentException("Invalid id: " + id); } } diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/SnowflakeIdGenerator.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/SnowflakeIdGenerator.java index f6d857ff5..a9643e108 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/SnowflakeIdGenerator.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/id/SnowflakeIdGenerator.java @@ -67,7 +67,7 @@ public class SnowflakeIdGenerator extends IdGenerator { if (this.idWorker == null) { throw new HugeException("Please initialize before using"); } - Id id = this.generate(this.idWorker.nextId()); + Id id = of(this.idWorker.nextId()); if (!this.forceString) { return id; } else { diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BinaryBackendEntry.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BinaryBackendEntry.java index daee5a110..09133aad0 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BinaryBackendEntry.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BinaryBackendEntry.java @@ -102,7 +102,7 @@ public class BinaryBackendEntry implements BackendEntry { if (this.columns.size() > 1) { Collections.sort(this.columns); } - return Collections.unmodifiableCollection(this.columns); + return Collections.unmodifiableList(this.columns); } @Override @@ -180,7 +180,7 @@ public class BinaryBackendEntry implements BackendEntry { @Override public Object asObject() { - return this.asBytes(); + return ByteBuffer.wrap(this.bytes); } @Override diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BinaryInlineSerializer.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BinaryInlineSerializer.java index 1b8a540e3..b94d06083 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BinaryInlineSerializer.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BinaryInlineSerializer.java @@ -22,13 +22,13 @@ package com.baidu.hugegraph.backend.serializer; import org.apache.commons.lang.NotImplementedException; import com.baidu.hugegraph.HugeGraph; +import com.baidu.hugegraph.backend.id.EdgeId; import com.baidu.hugegraph.backend.id.Id; import com.baidu.hugegraph.backend.store.BackendEntry; import com.baidu.hugegraph.backend.store.BackendEntry.BackendColumn; import com.baidu.hugegraph.schema.VertexLabel; import com.baidu.hugegraph.structure.HugeVertex; import com.baidu.hugegraph.structure.HugeVertexProperty; -import com.baidu.hugegraph.util.Bytes; public class BinaryInlineSerializer extends BinarySerializer { @@ -67,17 +67,18 @@ public class BinaryInlineSerializer extends BinarySerializer { // Parse id Id id = entry.id().origin(); - HugeVertex vertex = new HugeVertex(graph, id, VertexLabel.NONE); + Id vid = id.edge() ? ((EdgeId) id).ownerVertexId() : id; + HugeVertex vertex = new HugeVertex(graph, vid, VertexLabel.NONE); // Parse all properties and edges of a Vertex for (BackendColumn col : entry.columns()) { - if (Bytes.equals(entry.id().asBytes(), col.name)) { + if (id.edge()) { + // Parse vertex edges + this.parseColumn(col, vertex); + } else { // Parse vertex properties assert entry.columnsSize() == 1 : entry.columnsSize(); this.parseVertex(col.value, vertex); - } else { - // Parse vertex edges - this.parseColumn(col, vertex); } } diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BinarySerializer.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BinarySerializer.java index e10ef05cb..7cb34acba 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BinarySerializer.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BinarySerializer.java @@ -30,7 +30,6 @@ import com.baidu.hugegraph.backend.BackendException; import com.baidu.hugegraph.backend.id.EdgeId; import com.baidu.hugegraph.backend.id.Id; import com.baidu.hugegraph.backend.id.IdGenerator; -import com.baidu.hugegraph.backend.id.IdUtil; import com.baidu.hugegraph.backend.page.PageState; import com.baidu.hugegraph.backend.query.Condition; import com.baidu.hugegraph.backend.query.Condition.RangeConditions; @@ -162,7 +161,7 @@ public class BinarySerializer extends AbstractSerializer { } protected BackendColumn formatProperty(HugeProperty prop) { - BytesBuffer buffer = BytesBuffer.allocate(64); + BytesBuffer buffer = BytesBuffer.allocate(BytesBuffer.BUF_PROPERTY); buffer.writeProperty(prop.propertyKey(), prop.value()); return BackendColumn.of(this.formatPropertyName(prop), buffer.bytes()); } @@ -212,16 +211,8 @@ public class BinarySerializer extends AbstractSerializer { protected byte[] formatEdgeName(HugeEdge edge) { // owner-vertex + dir + edge-label + sort-values + other-vertex - - BytesBuffer buffer = BytesBuffer.allocate(256); - - buffer.writeId(edge.ownerVertex().id()); - buffer.write(edge.type().code()); - buffer.writeId(edge.schemaLabel().id()); - buffer.writeStringWithEnding(edge.name()); - buffer.writeId(edge.otherVertex().id()); - - return buffer.bytes(); + return BytesBuffer.allocate(BytesBuffer.BUF_EDGE_ID) + .writeEdgeId(edge.id()).bytes(); } protected byte[] formatEdgeValue(HugeEdge edge) { @@ -340,13 +331,13 @@ public class BinarySerializer extends AbstractSerializer { if (!type.isNumericIndex() && indexIdLengthExceedLimit(indexId)) { indexId = index.hashId(); } - String elemId = IdUtil.writeStoredString(index.elementId()); + Id elemId = index.elementId(); int idLen = 1 + elemId.length() + 1 + indexId.length(); buffer = BytesBuffer.allocate(idLen); // Write index-id buffer.writeIndexId(indexId, type); // Write element-id - buffer.writeString(elemId); + buffer.writeId(elemId); } return buffer.bytes(); @@ -363,8 +354,7 @@ public class BinarySerializer extends AbstractSerializer { if (this.indexWithIdPrefix) { buffer.readIndexId(index.type()); } - String elemId = buffer.readString(); - index.elementIds(IdUtil.readStoredString(elemId)); + index.elementIds(buffer.readId()); } } @@ -436,7 +426,7 @@ public class BinarySerializer extends AbstractSerializer { } @Override - public HugeEdge readEdge(HugeGraph graph, BackendEntry entry) { + public HugeEdge readEdge(HugeGraph graph, BackendEntry bytesEntry) { throw new NotImplementedException("Unsupported readEdge()"); } @@ -568,7 +558,7 @@ public class BinarySerializer extends AbstractSerializer { private Query writeQueryEdgePrefixCondition(ConditionQuery cq) { int count = 0; - BytesBuffer buffer = BytesBuffer.allocate(64); + BytesBuffer buffer = BytesBuffer.allocate(BytesBuffer.BUF_EDGE_ID); for (HugeKeys key : EdgeId.KEYS) { Object value = cq.condition(key); @@ -737,13 +727,8 @@ public class BinarySerializer extends AbstractSerializer { } else { edgeId = EdgeId.parse(id.asString()); } - BytesBuffer buffer = BytesBuffer.allocate(256); - buffer.writeId(edgeId.ownerVertexId()); - buffer.write(edgeId.direction().type().code()); - buffer.writeId(edgeId.edgeLabelId()); - buffer.writeStringWithEnding(edgeId.sortValues()); - buffer.writeId(edgeId.otherVertexId()); - + BytesBuffer buffer = BytesBuffer.allocate(BytesBuffer.BUF_EDGE_ID) + .writeEdgeId(edgeId); return new BinaryId(buffer.bytes(), id); } diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BytesBuffer.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BytesBuffer.java index 92abf50b6..39f2b7540 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BytesBuffer.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/BytesBuffer.java @@ -25,6 +25,7 @@ import java.util.Collection; import java.util.Date; import java.util.UUID; +import com.baidu.hugegraph.backend.id.EdgeId; import com.baidu.hugegraph.backend.id.Id; import com.baidu.hugegraph.backend.id.Id.IdType; import com.baidu.hugegraph.backend.id.IdGenerator; @@ -68,6 +69,9 @@ public final class BytesBuffer { public static final int DEFAULT_CAPACITY = 64; public static final int MAX_BUFFER_CAPACITY = 128 * 1024 * 1024; // 128M + public static final int BUF_EDGE_ID = 128; + public static final int BUF_PROPERTY = 64; + private ByteBuffer buffer; public BytesBuffer() { @@ -90,6 +94,10 @@ public final class BytesBuffer { return new BytesBuffer(capacity); } + public static BytesBuffer wrap(ByteBuffer buffer) { + return new BytesBuffer(buffer); + } + public static BytesBuffer wrap(byte[] array) { return new BytesBuffer(ByteBuffer.wrap(array)); } @@ -500,38 +508,47 @@ public final class BytesBuffer { } public BytesBuffer writeId(Id id, boolean big) { - if (id.number()) { - // Number Id - long value = id.asLong(); - this.writeNumber(value); - } else if (id.uuid()) { - // UUID Id - byte[] bytes = id.asBytes(); - assert bytes.length == Id.UUID_LENGTH; - this.writeUInt8(0x7f); // 0b01111111 means UUID - this.write(bytes); - } else { - // String Id - byte[] bytes = id.asBytes(); - int len = bytes.length; - E.checkArgument(len > 0, "Can't write empty id"); - if (!big) { - E.checkArgument(len <= ID_LEN_MAX, - "Id max length is %s, but got %s {%s}", - ID_LEN_MAX, len, id); - len -= 1; // mapping [1, 128] to [0, 127] - this.writeUInt8(len | 0x80); - } else { - E.checkArgument(len <= BIG_ID_LEN_MAX, - "Big id max length is %s, but got %s {%s}", - BIG_ID_LEN_MAX, len, id); - len -= 1; - int high = len >> 8; - int low = len & 0xff; - this.writeUInt8(high | 0x80); - this.writeUInt8(low); - } - this.write(bytes); + switch (id.type()) { + case LONG: + // Number Id + long value = id.asLong(); + this.writeNumber(value); + break; + case UUID: + // UUID Id + byte[] bytes = id.asBytes(); + assert bytes.length == Id.UUID_LENGTH; + this.writeUInt8(0x7f); // 0b01111111 means UUID + this.write(bytes); + break; + case EDGE: + // Edge Id + this.writeUInt8(0x7e); // 0b01111110 means EdgeId + this.writeEdgeId(id); + break; + default: + // String Id + bytes = id.asBytes(); + int len = bytes.length; + E.checkArgument(len > 0, "Can't write empty id"); + if (!big) { + E.checkArgument(len <= ID_LEN_MAX, + "Id max length is %s, but got %s {%s}", + ID_LEN_MAX, len, id); + len -= 1; // mapping [1, 128] to [0, 127] + this.writeUInt8(len | 0x80); + } else { + E.checkArgument(len <= BIG_ID_LEN_MAX, + "Big id max length is %s, but got %s {%s}", + BIG_ID_LEN_MAX, len, id); + len -= 1; + int high = len >> 8; + int low = len & 0xff; + this.writeUInt8(high | 0x80); + this.writeUInt8(low); + } + this.write(bytes); + break; } return this; } @@ -544,12 +561,16 @@ public final class BytesBuffer { byte b = this.read(); boolean number = (b & 0x80) == 0; if (number) { - // UUID Id if (b == 0x7f) { + // UUID Id return IdGenerator.of(this.read(Id.UUID_LENGTH), IdType.UUID); + } else if (b == 0x7e) { + // Edge Id + return this.readEdgeId(); + } else { + // Number Id + return IdGenerator.of(this.readNumber(b)); } - // Number Id - return IdGenerator.of(this.readNumber(b)); } else { // String Id int len = b & ID_LEN_MASK; @@ -564,6 +585,22 @@ public final class BytesBuffer { } } + public BytesBuffer writeEdgeId(Id id) { + EdgeId edge = (EdgeId) id; + this.writeId(edge.ownerVertexId()); + this.write(edge.directionCode()); + this.writeId(edge.edgeLabelId()); + this.writeStringWithEnding(edge.sortValues()); + this.writeId(edge.otherVertexId()); + return this; + } + + public Id readEdgeId() { + return new EdgeId(this.readId(), EdgeId.directionFromCode(this.read()), + this.readId(), this.readStringWithEnding(), + this.readId()); + } + public BytesBuffer writeIndexId(Id id, HugeType type) { return this.writeIndexId(id, type, true); } @@ -642,6 +679,7 @@ public final class BytesBuffer { * 0b 0111 0000 X X X X X X X X [-2^64, -1] * * NOTE: 0b 0111 1111 is used by 128 bits UUID + * 0b 0111 1110 is used by EdgeId */ int positive = val >= 0 ? 0x08 : 0x00; if (~0x7ffL <= val && val <= 0x7ffL) { diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/SerializerFactory.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/SerializerFactory.java index 789f7aee3..7b51ebad3 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/SerializerFactory.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/SerializerFactory.java @@ -44,7 +44,7 @@ public class SerializerFactory { Class clazz = serializers.get(name); if (clazz == null) { - throw new BackendException("Not exists serializer: %s", name); + throw new BackendException("Not exists serializer: '%s'", name); } assert AbstractSerializer.class.isAssignableFrom(clazz); @@ -62,13 +62,13 @@ public class SerializerFactory { try { clazz = classLoader.loadClass(classPath); } catch (Exception e) { - throw new BackendException(e); + throw new BackendException("Invalid class: '%s'", e, classPath); } // Check subclass if (!AbstractSerializer.class.isAssignableFrom(clazz)) { - throw new BackendException("Class '%s' is not a subclass of " + - "class AbstractSerializer", classPath); + throw new BackendException("Class is not a subclass of class " + + "AbstractSerializer: '%s'", classPath); } // Check exists diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/TableBackendEntry.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/TableBackendEntry.java index 45681be9d..6a767289c 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/TableBackendEntry.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/TableBackendEntry.java @@ -28,6 +28,8 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import org.apache.commons.lang3.NotImplementedException; + import com.baidu.hugegraph.backend.id.Id; import com.baidu.hugegraph.backend.store.BackendEntry; import com.baidu.hugegraph.type.HugeType; @@ -82,11 +84,17 @@ public class TableBackendEntry implements BackendEntry { this.column(key, value); break; case SET: - this.columns.putIfAbsent(key, new LinkedHashSet<>()); + // Avoid creating new Set when the key exists + if (!this.columns.containsKey(key)) { + this.columns.putIfAbsent(key, new LinkedHashSet<>()); + } this.>column(key).add(value); break; case LIST: - this.columns.putIfAbsent(key, new LinkedList<>()); + // Avoid creating new List when the key exists + if (!this.columns.containsKey(key)) { + this.columns.putIfAbsent(key, new LinkedList<>()); + } this.>column(key).add(value); break; default: @@ -95,7 +103,9 @@ public class TableBackendEntry implements BackendEntry { } public void column(HugeKeys key, Object name, T value) { - this.columns.putIfAbsent(key, new ConcurrentHashMap<>()); + if (!this.columns.containsKey(key)) { + this.columns.putIfAbsent(key, new ConcurrentHashMap<>()); + } this.>column(key).put(name, value); } @@ -206,31 +216,31 @@ public class TableBackendEntry implements BackendEntry { @Override public int columnsSize() { - throw new RuntimeException("Not supported by table backend"); + throw new NotImplementedException("Not supported by table backend"); } @Override public Collection columns() { - throw new RuntimeException("Not supported by table backend"); + throw new NotImplementedException("Not supported by table backend"); } @Override public void columns(Collection bytesColumns) { - throw new RuntimeException("Not supported by table backend"); + throw new NotImplementedException("Not supported by table backend"); } @Override public void columns(BackendEntry.BackendColumn... bytesColumns) { - throw new RuntimeException("Not supported by table backend"); + throw new NotImplementedException("Not supported by table backend"); } @Override public void merge(BackendEntry other) { - throw new RuntimeException("Not supported by table backend"); + throw new NotImplementedException("Not supported by table backend"); } @Override public void clear() { - throw new RuntimeException("Not supported by table backend"); + throw new NotImplementedException("Not supported by table backend"); } } diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/TableSerializer.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/TableSerializer.java index ee15a087e..4f3cb636e 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/TableSerializer.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/serializer/TableSerializer.java @@ -84,18 +84,18 @@ public abstract class TableSerializer extends AbstractSerializer { @Override protected abstract TableBackendEntry convertEntry(BackendEntry backendEntry); - protected void formatProperty(HugeProperty prop, + protected void formatProperty(HugeProperty property, TableBackendEntry.Row row) { - long pkid = prop.propertyKey().id().asLong(); - row.column(HugeKeys.PROPERTIES, pkid, JsonUtil.toJson(prop.value())); + long pkid = property.propertyKey().id().asLong(); + row.column(HugeKeys.PROPERTIES, pkid, this.writeProperty(property)); } - protected void parseProperty(Id key, String colValue, HugeElement owner) { - // Get PropertyKey by PropertyKey name + protected void parseProperty(Id key, Object colValue, HugeElement owner) { + // Get PropertyKey by PropertyKey id PropertyKey pkey = owner.graph().propertyKey(key); // Parse value - Object value = JsonUtil.fromJson(colValue, pkey.implementClazz()); + Object value = this.readProperty(pkey, colValue); // Set properties of vertex/edge if (pkey.cardinality() == Cardinality.SINGLE) { @@ -103,27 +103,44 @@ public abstract class TableSerializer extends AbstractSerializer { } else { if (!(value instanceof Collection)) { throw new BackendException( - "Invalid value of non-single property: %s", - value); - } - for (Object v : (Collection) value) { - v = JsonUtil.castNumber(v, pkey.dataType().clazz()); - owner.addProperty(pkey, v); + "Invalid value of non-single property: %s", value); } + owner.addProperty(pkey, value); } } + protected Object writeProperty(HugeProperty property) { + return this.writeProperty(property.value()); + } + + protected Object writeProperty(Object value) { + return JsonUtil.toJson(value); + } + + @SuppressWarnings("unchecked") + protected T readProperty(PropertyKey pkey, Object value) { + Class clazz = (Class) pkey.implementClazz(); + T result = JsonUtil.fromJson(value.toString(), clazz); + if (pkey.cardinality() != Cardinality.SINGLE) { + Collection values = (Collection) result; + List newValues = new ArrayList<>(values.size()); + for (Object v : values) { + newValues.add(JsonUtil.castNumber(v, pkey.dataType().clazz())); + } + result = (T) newValues; + } + return result; + } + protected TableBackendEntry.Row formatEdge(HugeEdge edge) { EdgeId id = edge.idWithDirection(); TableBackendEntry.Row row = new TableBackendEntry.Row(edge.type(), id); // Id: ownerVertex + direction + edge-label + sortValues + otherVertex - row.column(HugeKeys.OWNER_VERTEX, - IdUtil.writeStoredString(id.ownerVertexId())); - row.column(HugeKeys.DIRECTION, id.direction().code()); + row.column(HugeKeys.OWNER_VERTEX, this.writeId(id.ownerVertexId())); + row.column(HugeKeys.DIRECTION, id.directionCode()); row.column(HugeKeys.LABEL, id.edgeLabelId().asLong()); row.column(HugeKeys.SORT_VALUES, id.sortValues()); - row.column(HugeKeys.OTHER_VERTEX, - IdUtil.writeStoredString(id.otherVertexId())); + row.column(HugeKeys.OTHER_VERTEX, this.writeId(id.otherVertexId())); this.formatProperties(edge, row); return row; @@ -138,16 +155,15 @@ public abstract class TableSerializer extends AbstractSerializer { */ protected HugeEdge parseEdge(TableBackendEntry.Row row, HugeVertex vertex, HugeGraph graph) { - String ownerVertexId = row.column(HugeKeys.OWNER_VERTEX); + Object ownerVertexId = row.column(HugeKeys.OWNER_VERTEX); Number dir = row.column(HugeKeys.DIRECTION); - Directions direction = SerialEnum.fromCode(Directions.class, - dir.byteValue()); + Directions direction = EdgeId.directionFromCode(dir.byteValue()); Number label = row.column(HugeKeys.LABEL); String sortValues = row.column(HugeKeys.SORT_VALUES); - String otherVertexId = row.column(HugeKeys.OTHER_VERTEX); + Object otherVertexId = row.column(HugeKeys.OTHER_VERTEX); if (vertex == null) { - Id ownerId = IdUtil.readStoredString(ownerVertexId); + Id ownerId = this.readId(ownerVertexId); vertex = new HugeVertex(graph, ownerId, null); } @@ -155,7 +171,7 @@ public abstract class TableSerializer extends AbstractSerializer { VertexLabel srcLabel = graph.vertexLabel(edgeLabel.sourceLabel()); VertexLabel tgtLabel = graph.vertexLabel(edgeLabel.targetLabel()); - Id otherId = IdUtil.readStoredString(otherVertexId); + Id otherId = this.readId(otherVertexId); boolean isOutEdge = direction == Directions.OUT; HugeVertex otherVertex; if (isOutEdge) { @@ -190,7 +206,7 @@ public abstract class TableSerializer extends AbstractSerializer { @Override public BackendEntry writeVertex(HugeVertex vertex) { TableBackendEntry entry = newBackendEntry(vertex); - entry.column(HugeKeys.ID, IdUtil.writeStoredString(vertex.id())); + entry.column(HugeKeys.ID, this.writeId(vertex.id())); entry.column(HugeKeys.LABEL, vertex.schemaLabel().id().asLong()); // Add all properties of a Vertex this.formatProperties(vertex, entry.row()); @@ -202,7 +218,7 @@ public abstract class TableSerializer extends AbstractSerializer { HugeVertex vertex = prop.element(); TableBackendEntry entry = newBackendEntry(vertex); entry.subId(IdGenerator.of(prop.key())); - entry.column(HugeKeys.ID, IdUtil.writeStoredString(vertex.id())); + entry.column(HugeKeys.ID, this.writeId(vertex.id())); entry.column(HugeKeys.LABEL, vertex.schemaLabel().id().asLong()); this.formatProperty(prop, entry.row()); @@ -219,7 +235,7 @@ public abstract class TableSerializer extends AbstractSerializer { TableBackendEntry entry = this.convertEntry(backendEntry); assert entry.type().isVertex(); - Id id = IdUtil.readStoredString(entry.column(HugeKeys.ID)); + Id id = this.readId(entry.column(HugeKeys.ID)); Number label = entry.column(HugeKeys.LABEL); VertexLabel vertexLabel = VertexLabel.NONE; @@ -248,13 +264,11 @@ public abstract class TableSerializer extends AbstractSerializer { EdgeId id = edge.idWithDirection(); TableBackendEntry.Row row = new TableBackendEntry.Row(edge.type(), id); // Id: ownerVertex + direction + edge-label + sortValues + otherVertex - row.column(HugeKeys.OWNER_VERTEX, - IdUtil.writeStoredString(id.ownerVertexId())); - row.column(HugeKeys.DIRECTION, id.direction().code()); + row.column(HugeKeys.OWNER_VERTEX, this.writeId(id.ownerVertexId())); + row.column(HugeKeys.DIRECTION, id.directionCode()); row.column(HugeKeys.LABEL, id.edgeLabelId().asLong()); row.column(HugeKeys.SORT_VALUES, id.sortValues()); - row.column(HugeKeys.OTHER_VERTEX, - IdUtil.writeStoredString(id.otherVertexId())); + row.column(HugeKeys.OTHER_VERTEX, this.writeId(id.otherVertexId())); // Format edge property this.formatProperty(prop, row); @@ -286,8 +300,7 @@ public abstract class TableSerializer extends AbstractSerializer { } else { entry.column(HugeKeys.FIELD_VALUES, index.fieldValues()); entry.column(HugeKeys.INDEX_LABEL_ID, index.indexLabel().longId()); - entry.column(HugeKeys.ELEMENT_IDS, - IdUtil.writeStoredString(index.elementId())); + entry.column(HugeKeys.ELEMENT_IDS, this.writeId(index.elementId())); entry.subId(index.elementId()); } return entry; @@ -305,13 +318,13 @@ public abstract class TableSerializer extends AbstractSerializer { Object indexValues = entry.column(HugeKeys.FIELD_VALUES); Number indexLabelId = entry.column(HugeKeys.INDEX_LABEL_ID); - Set elemIds = this.parseIndexElemIds(entry); + Set elemIds = this.parseIndexElemIds(entry); IndexLabel indexLabel = graph.indexLabel(this.toId(indexLabelId)); HugeIndex index = new HugeIndex(indexLabel); index.fieldValues(indexValues); - for (String elemId : elemIds) { - index.elementIds(IdUtil.readStoredString(elemId)); + for (Object elemId : elemIds) { + index.elementIds(this.readId(elemId)); } return index; } @@ -328,7 +341,7 @@ public abstract class TableSerializer extends AbstractSerializer { id = EdgeId.parse(id.asString()); } } else if (type.isGraph()) { - id = IdGenerator.of(IdUtil.writeStoredString(id)); + id = IdGenerator.of(this.writeId(id)); } return id; } @@ -342,14 +355,13 @@ public abstract class TableSerializer extends AbstractSerializer { if (r.key() == HugeKeys.OWNER_VERTEX || r.key() == HugeKeys.OTHER_VERTEX) { // Serialize vertex id - String id = IdUtil.writeStoredString((Id) value); - r.serialValue(this.escapeString(id)); + r.serialValue(this.writeId((Id) value)); } else { // Serialize label id r.serialValue(((Id) value).asObject()); } } else if (value instanceof Directions) { - r.serialValue(((Directions) value).code()); + r.serialValue(((Directions) value).type().code()); } } return null; @@ -377,7 +389,7 @@ public abstract class TableSerializer extends AbstractSerializer { if (query.resultType().isGraph() && r.relation() == Condition.RelationType.CONTAINS_VALUE) { - r.serialValue(JsonUtil.toJson(r.serialValue())); + r.serialValue(this.writeProperty(r.serialValue())); } } @@ -587,7 +599,7 @@ public abstract class TableSerializer extends AbstractSerializer { protected abstract Object toLongList(Collection ids); - protected abstract Set parseIndexElemIds(TableBackendEntry entry); + protected abstract Set parseIndexElemIds(TableBackendEntry entry); protected abstract void formatProperties(HugeElement element, TableBackendEntry.Row row); @@ -595,17 +607,18 @@ public abstract class TableSerializer extends AbstractSerializer { protected abstract void parseProperties(HugeElement element, TableBackendEntry.Row row); + protected Object writeId(Id id) { + return IdUtil.writeStoredString(id); + } + + protected Id readId(Object id) { + return IdUtil.readStoredString(id.toString()); + } + protected Object serializeValue(Object value) { if (value instanceof Id) { value = ((Id) value).asObject(); } - if (value instanceof String) { - value = this.escapeString((String) value); - } - return value; - } - - protected String escapeString(String value) { return value; } diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/type/HugeType.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/type/HugeType.java index 5193bad93..78c93ae50 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/type/HugeType.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/type/HugeType.java @@ -170,4 +170,8 @@ public enum HugeType implements SerialEnum { public static HugeType fromString(String type) { return ALL_NAME.get(type); } + + public static HugeType fromCode(byte code) { + return SerialEnum.fromCode(HugeType.class, code); + } } diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/type/define/DataType.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/type/define/DataType.java index 906bc1f83..9bb9a0f1f 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/type/define/DataType.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/type/define/DataType.java @@ -22,6 +22,7 @@ package com.baidu.hugegraph.type.define; import java.util.Date; import java.util.UUID; +import com.baidu.hugegraph.HugeException; import com.baidu.hugegraph.util.DateUtil; public enum DataType implements SerialEnum { @@ -161,4 +162,13 @@ public enum DataType implements SerialEnum { } return null; } + + public static DataType fromClass(Class clazz) { + for (DataType type : DataType.values()) { + if (type.clazz() == clazz) { + return type; + } + } + throw new HugeException("Unknow clazz '%s' for DataType", clazz); + } } diff --git a/hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseStoreProvider.java b/hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseStoreProvider.java index 5747c29ad..c7a0b3d12 100644 --- a/hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseStoreProvider.java +++ b/hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseStoreProvider.java @@ -57,7 +57,8 @@ public class HbaseStoreProvider extends AbstractBackendStoreProvider { * also split range table to rangeInt, rangeFloat, * rangeLong and rangeDouble * [1.5] #633: support unique index + * [1.6] #680: update index element-id to bin format */ - return "1.5"; + return "1.6"; } } diff --git a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlBackendEntry.java b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlBackendEntry.java index f60fb12c8..2449a4dcc 100644 --- a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlBackendEntry.java +++ b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlBackendEntry.java @@ -19,11 +19,8 @@ package com.baidu.hugegraph.backend.store.mysql; -import java.util.Collection; - import com.baidu.hugegraph.backend.id.Id; import com.baidu.hugegraph.backend.serializer.TableBackendEntry; -import com.baidu.hugegraph.backend.store.BackendEntry; import com.baidu.hugegraph.type.HugeType; public class MysqlBackendEntry extends TableBackendEntry { @@ -43,41 +40,4 @@ public class MysqlBackendEntry extends TableBackendEntry { public MysqlBackendEntry(TableBackendEntry.Row row) { super(row); } - - @Override - public String toString() { - return String.format("MysqlBackendEntry{%s, sub-rows: %s}", - this.row().toString(), - this.subRows().toString()); - } - - @Override - public int columnsSize() { - throw new RuntimeException("Not supported by MySQL"); - } - - @Override - public Collection columns() { - throw new RuntimeException("Not supported by MySQL"); - } - - @Override - public void columns(Collection bytesColumns) { - throw new RuntimeException("Not supported by MySQL"); - } - - @Override - public void columns(BackendColumn... bytesColumns) { - throw new RuntimeException("Not supported by MySQL"); - } - - @Override - public void merge(BackendEntry other) { - throw new RuntimeException("Not supported by MySQL"); - } - - @Override - public void clear() { - throw new RuntimeException("Not supported by MySQL"); - } } diff --git a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlSerializer.java b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlSerializer.java index cda08f86e..bdd5498c3 100644 --- a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlSerializer.java +++ b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlSerializer.java @@ -59,8 +59,8 @@ public class MysqlSerializer extends TableSerializer { } @Override - protected Set parseIndexElemIds(TableBackendEntry entry) { - Set elemIds = InsertionOrderUtil.newSet(); + protected Set parseIndexElemIds(TableBackendEntry entry) { + Set elemIds = InsertionOrderUtil.newSet(); elemIds.add(entry.column(HugeKeys.ELEMENT_IDS)); for (TableBackendEntry.Row row : entry.subRows()) { elemIds.add(row.column(HugeKeys.ELEMENT_IDS)); @@ -162,9 +162,4 @@ public class MysqlSerializer extends TableSerializer { schema.userdata(e.getKey(), e.getValue()); } } - - @Override - protected String escapeString(String value) { - return MysqlUtil.escapeString(value); - } } diff --git a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlStoreProvider.java b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlStoreProvider.java index 455939a53..126e4d622 100644 --- a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlStoreProvider.java +++ b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlStoreProvider.java @@ -74,7 +74,8 @@ public class MysqlStoreProvider extends AbstractBackendStoreProvider { * also split range table to rangeInt, rangeFloat, * rangeLong and rangeDouble * [1.4] #633: support unique index + * [1.5] #661: reduce the storage of vertex/edge id */ - return "1.4"; + return "1.5"; } } diff --git a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlTable.java b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlTable.java index ece5f23e1..20eb87027 100644 --- a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlTable.java +++ b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlTable.java @@ -43,7 +43,6 @@ import com.baidu.hugegraph.backend.store.TableDefine; import com.baidu.hugegraph.backend.store.mysql.MysqlEntryIterator.PagePosition; import com.baidu.hugegraph.backend.store.mysql.MysqlSessions.Session; import com.baidu.hugegraph.exception.NotFoundException; -import com.baidu.hugegraph.exception.NotSupportException; import com.baidu.hugegraph.iterator.ExtendableIterator; import com.baidu.hugegraph.type.define.HugeKeys; import com.baidu.hugegraph.util.Log; @@ -195,8 +194,8 @@ public abstract class MysqlTable delete.append("DELETE FROM ").append(this.table()); this.appendPartition(delete); - WhereBuilder where = new WhereBuilder(); - where.and(formatKeys(idNames), "?"); + WhereBuilder where = this.newWhereBuilder(); + where.and(formatKeys(idNames), "="); delete.append(where.build()); this.deleteTemplate = delete.toString(); @@ -381,7 +380,7 @@ public abstract class MysqlTable values.add(objects.get(0)); } - WhereBuilder where = new WhereBuilder(); + WhereBuilder where = this.newWhereBuilder(); where.in(formatKey(nameParts.get(0)), values); select.append(where.build()); return ImmutableList.of(select); @@ -402,7 +401,7 @@ public abstract class MysqlTable * NOTE: concat with AND relation, like: * "pk = id and ck1 = v1 and ck2 = v2" */ - WhereBuilder where = new WhereBuilder(); + WhereBuilder where = this.newWhereBuilder(); where.and(formatKeys(nameParts), objects); idSelection.append(where.build()); @@ -419,7 +418,7 @@ public abstract class MysqlTable for (Condition condition : conditions) { clauses.add(this.condition2Sql(condition)); } - WhereBuilder where = new WhereBuilder(); + WhereBuilder where = this.newWhereBuilder(); where.and(clauses); select.append(where.build()); return ImmutableList.of(select); @@ -450,40 +449,17 @@ public abstract class MysqlTable String key = relation.serialKey().toString(); Object value = relation.serialValue(); - StringBuilder sql = new StringBuilder(32); - sql.append(key); - switch (relation.relation()) { - case EQ: - sql.append(" = ").append(value); - break; - case NEQ: - sql.append(" != ").append(value); - break; - case GT: - sql.append(" > ").append(value); - break; - case GTE: - sql.append(" >= ").append(value); - break; - case LT: - sql.append(" < ").append(value); - break; - case LTE: - sql.append(" <= ").append(value); - break; - case IN: - sql.append(" IN ("); - String values = Strings.join((List) value, ','); - sql.append(values); - sql.append(")"); - break; - case CONTAINS_VALUE: - case CONTAINS_KEY: - case SCAN: - default: - throw new NotSupportException("relation '%s'", relation); - } - return sql; + WhereBuilder sql = this.newWhereBuilder(false); + sql.relation(key, relation.relation(), value); + return sql.build(); + } + + protected WhereBuilder newWhereBuilder() { + return this.newWhereBuilder(true); + } + + protected WhereBuilder newWhereBuilder(boolean startWithWhere) { + return new WhereBuilder(startWithWhere); } protected void wrapOrderBy(StringBuilder select, Query query) { @@ -526,7 +502,7 @@ public abstract class MysqlTable // Need add `where` to `select` when query is IdQuery boolean startWithWhere = query.conditions().isEmpty(); - WhereBuilder where = new WhereBuilder(startWithWhere); + WhereBuilder where = this.newWhereBuilder(startWithWhere); where.gte(formatKeys(idColumnNames), values); if (!startWithWhere) { select.append(" AND"); diff --git a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlTables.java b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlTables.java index 93d418224..cbf59dbc6 100644 --- a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlTables.java +++ b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlTables.java @@ -287,7 +287,9 @@ public class MysqlTables { @Override public List idColumnValue(Id id) { EdgeId edgeId; - if (!(id instanceof EdgeId)) { + if (id instanceof EdgeId) { + edgeId = (EdgeId) id; + } else { String[] idParts = EdgeId.split(id); if (idParts.length == 1) { // Delete edge by label @@ -295,8 +297,6 @@ public class MysqlTables { } id = IdUtil.readString(id.asString()); edgeId = EdgeId.parse(id.asString()); - } else { - edgeId = (EdgeId) id; } E.checkState(edgeId.direction() == this.direction, @@ -305,7 +305,7 @@ public class MysqlTables { List list = new ArrayList<>(5); list.add(IdUtil.writeStoredString(edgeId.ownerVertexId())); - list.add(edgeId.direction().code()); + list.add(edgeId.directionCode()); list.add(edgeId.edgeLabelId().asLong()); list.add(edgeId.sortValues()); list.add(IdUtil.writeStoredString(edgeId.otherVertexId())); diff --git a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlUtil.java b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlUtil.java index 402024fb9..4ef6c950f 100644 --- a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlUtil.java +++ b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlUtil.java @@ -21,94 +21,111 @@ package com.baidu.hugegraph.backend.store.mysql; public class MysqlUtil { + public static String escapeAndWrapString(String value) { + return escapeString(value, true); + } + public static String escapeString(String value) { + return escapeString(value, false); + } + + private static String escapeString(String value, boolean wrap) { int length = value.length(); if (!isEscapeNeededForString(value, length)) { + if (!wrap) { + return value; + } StringBuilder buf = new StringBuilder(length + 2); buf.append('\'').append(value).append('\''); return buf.toString(); } - StringBuilder buf = new StringBuilder((int) (length * 1.1D)); - buf.append('\''); + StringBuilder buffer = new StringBuilder((int) (length * 1.1d)); + + if (wrap) { + buffer.append('\''); + } for (int i = 0; i < length; ++i) { char c = value.charAt(i); switch (c) { case '\u0000': - buf.append('\\'); - buf.append('0'); + buffer.append('\\'); + buffer.append('0'); break; case '\n': - buf.append('\\'); - buf.append('n'); + buffer.append('\\'); + buffer.append('n'); break; case '\r': - buf.append('\\'); - buf.append('r'); + buffer.append('\\'); + buffer.append('r'); break; case '\u001a': - buf.append('\\'); - buf.append('Z'); + buffer.append('\\'); + buffer.append('Z'); break; case '"': /* * Doesn't need to add '\', because we wrap string with "'" * Assume that we don't use Ansi Mode */ - buf.append('"'); + buffer.append('"'); break; case '\'': - buf.append('\\'); - buf.append('\''); + buffer.append('\\'); + buffer.append('\''); break; case '\\': - buf.append('\\'); - buf.append('\\'); + buffer.append('\\'); + buffer.append('\\'); break; default: - buf.append(c); + buffer.append(c); break; } } - buf.append('\''); - return buf.toString(); + if (wrap) { + buffer.append('\''); + } + + return buffer.toString(); } public static boolean isEscapeNeededForString(String sql, int length) { - boolean needsHesqlEscape = false; + boolean needsEscape = false; for (int i = 0; i < length; ++i) { char c = sql.charAt(i); switch (c) { case '\u0000': - needsHesqlEscape = true; + needsEscape = true; break; case '\n': - needsHesqlEscape = true; + needsEscape = true; break; case '\r': - needsHesqlEscape = true; + needsEscape = true; break; case '\u001a': - needsHesqlEscape = true; + needsEscape = true; break; case '\'': - needsHesqlEscape = true; + needsEscape = true; break; case '\\': - needsHesqlEscape = true; + needsEscape = true; break; default: break; } - if (needsHesqlEscape) { + if (needsEscape) { break; } } - return needsHesqlEscape; + return needsEscape; } } diff --git a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/WhereBuilder.java b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/WhereBuilder.java index 9e7998648..743cd2ef5 100644 --- a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/WhereBuilder.java +++ b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/WhereBuilder.java @@ -21,6 +21,8 @@ package com.baidu.hugegraph.backend.store.mysql; import java.util.List; +import com.baidu.hugegraph.backend.query.Condition.RelationType; +import com.baidu.hugegraph.exception.NotSupportException; import com.baidu.hugegraph.util.E; public class WhereBuilder { @@ -39,30 +41,72 @@ public class WhereBuilder { } } - /** - * Concat as: key1 = value and key2 = value... - * @param keys the keys to be concatted with value - * @param value the value to be concatted with every key - */ - public void and(List keys, String value) { - this.and(keys, " = ", value); + public WhereBuilder relation(String key, RelationType type, Object value) { + String operator = null; + switch (type) { + case EQ: + operator = "="; + break; + case NEQ: + operator = "!="; + break; + case GT: + operator = ">"; + break; + case GTE: + operator = ">="; + break; + case LT: + operator = "<"; + break; + case LTE: + operator = "<="; + break; + case IN: + @SuppressWarnings("unchecked") + List values = (List) value; + this.in(key, values); + break; + case CONTAINS_VALUE: + case CONTAINS_KEY: + case SCAN: + default: + throw new NotSupportException("relation '%s'", type); + } + if (operator != null) { + this.builder.append(key); + this.builder.append(operator); + this.builder.append(wrapStringIfNeeded(value)); + } + return this; } /** - * Concat as: key1 op value and key2 op value... + * Concat as: cond1 and cond2... + * @return WhereBuilder + */ + public WhereBuilder and() { + this.builder.append(" AND "); + return this; + } + + /** + * Concat as: key1 op ? and key2 op ?... * @param keys the keys to be concatted with value * @param operator the operator to link every key and value pair * @param value the value to be concatted with every key + * @return WhereBuilder */ - public void and(List keys, String operator, String value) { + public WhereBuilder and(List keys, String operator) { for (int i = 0, n = keys.size(); i < n; i++) { this.builder.append(keys.get(i)); this.builder.append(operator); - this.builder.append(value); + this.builder.append("?"); if (i != n - 1) { this.builder.append(" AND "); } } + return this; } /** @@ -71,9 +115,10 @@ public class WhereBuilder { * same index * @param values the values to be concatted with every keys according to * the same index + * @return WhereBuilder */ - public void and(List keys, List values) { - this.and(keys, " = ", values); + public WhereBuilder and(List keys, List values) { + return this.and(keys, "=", values); } /** @@ -83,8 +128,11 @@ public class WhereBuilder { * @param operator the operator to link every key and value pair * @param values the values to be concatted with every keys according to * the same index + * @return WhereBuilder */ - public void and(List keys, String operator, List values) { + public WhereBuilder and(List keys, + String operator, + List values) { E.checkArgument(keys.size() == values.size(), "The size of keys '%s' is not equal with " + "values size '%s'", @@ -93,16 +141,12 @@ public class WhereBuilder { for (int i = 0, n = keys.size(); i < n; i++) { this.builder.append(keys.get(i)); this.builder.append(operator); - Object value = values.get(i); - if (value instanceof String) { - this.builder.append(MysqlUtil.escapeString((String) value)); - } else { - this.builder.append(value); - } + this.builder.append(wrapStringIfNeeded(values.get(i))); if (i != n - 1) { this.builder.append(" AND "); } } + return this; } /** @@ -113,10 +157,11 @@ public class WhereBuilder { * according to the same index * @param values the values to be concatted with every keys according to * the same index + * @return WhereBuilder */ - public void and(List keys, - List operators, - List values) { + public WhereBuilder and(List keys, + List operators, + List values) { E.checkArgument(keys.size() == operators.size(), "The size of keys '%s' is not equal with " + "operators size '%s'", @@ -129,23 +174,20 @@ public class WhereBuilder { for (int i = 0, n = keys.size(); i < n; i++) { this.builder.append(keys.get(i)); this.builder.append(operators.get(i)); - Object value = values.get(i); - if (value instanceof String) { - this.builder.append(MysqlUtil.escapeString((String) value)); - } else { - this.builder.append(value); - } + this.builder.append(wrapStringIfNeeded(values.get(i))); if (i != n - 1) { this.builder.append(" AND "); } } + return this; } /** * Concat as: clause1 and clause2... * @param clauses the clauses to be concatted with 'AND' operator + * @return WhereBuilder */ - public void and(List clauses) { + public WhereBuilder and(List clauses) { E.checkArgument(clauses != null && !clauses.isEmpty(), "The clauses can't be empty"); @@ -157,35 +199,34 @@ public class WhereBuilder { this.builder.append(" AND "); } } + return this; } /** * Concat as: key in (value1, value2...) * @param key the key to be concatted with 'IN' operator * @param values the values to be concated with ',' and wappred by '()' + * @return WhereBuilder */ - public void in(String key, List values) { + public WhereBuilder in(String key, List values) { this.builder.append(key).append(" IN ("); for (int i = 0, n = values.size(); i < n; i++) { - Object value = values.get(i); - if (value instanceof String) { - this.builder.append(MysqlUtil.escapeString((String) value)); - } else { - this.builder.append(value); - } + this.builder.append(wrapStringIfNeeded(values.get(i))); if (i != n - 1) { this.builder.append(", "); } } this.builder.append(")"); + return this; } /** * Concat as: (key1, key2...keyn) {@code >=} (val1, val2...valn) * @param keys the keys to be concatted with {@code >=} operator * @param values the values to be concatted with {@code >=} operator + * @return WhereBuilder */ - public void gte(List keys, List values) { + public WhereBuilder gte(List keys, List values) { E.checkArgument(keys.size() == values.size(), "The size of keys '%s' is not equal with " + "values size '%s'", @@ -199,25 +240,33 @@ public class WhereBuilder { } this.builder.append(") >= ("); for (int i = 0, n = values.size(); i < n; i++) { - Object value = values.get(i); - if (value instanceof String) { - this.builder.append(MysqlUtil.escapeString((String) value)); - } else { - this.builder.append(value); - } + this.builder.append(wrapStringIfNeeded(values.get(i))); if (i != n - 1) { this.builder.append(", "); } } this.builder.append(")"); + return this; } - public String build() { - return this.builder.toString(); + public StringBuilder build() { + return this.builder; } @Override public String toString() { return this.builder.toString(); } + + protected String wrapStringIfNeeded(Object value) { + if (value instanceof String) { + return this.escapeAndWrapString((String) value); + } else { + return String.valueOf(value); + } + } + + protected String escapeAndWrapString(String value) { + return MysqlUtil.escapeAndWrapString(value); + } } diff --git a/hugegraph-palo/src/main/java/com/baidu/hugegraph/backend/store/palo/PaloStoreProvider.java b/hugegraph-palo/src/main/java/com/baidu/hugegraph/backend/store/palo/PaloStoreProvider.java index 3ff600c91..8f7159f2e 100644 --- a/hugegraph-palo/src/main/java/com/baidu/hugegraph/backend/store/palo/PaloStoreProvider.java +++ b/hugegraph-palo/src/main/java/com/baidu/hugegraph/backend/store/palo/PaloStoreProvider.java @@ -58,8 +58,9 @@ public class PaloStoreProvider extends MysqlStoreProvider { * also split range table to rangeInt, rangeFloat, * rangeLong and rangeDouble * [1.4] #633: support unique index + * [1.5] #661: reduce the storage of vertex/edge id */ - return "1.4"; + return "1.5"; } public static class PaloSchemaStore extends PaloStore { diff --git a/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlSerializer.java b/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlSerializer.java index 3d1590264..aa152b75c 100644 --- a/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlSerializer.java +++ b/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlSerializer.java @@ -52,12 +52,4 @@ public class PostgresqlSerializer extends MysqlSerializer { } return entry; } - - @Override - protected String escapeString(String value) { - if (value.equals("\u0000")) { - return "\'\'"; - } - return PostgresqlSessions.escapeString(value); - } } diff --git a/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlSessions.java b/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlSessions.java index 0927db856..1dc83637f 100644 --- a/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlSessions.java +++ b/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlSessions.java @@ -52,7 +52,7 @@ public class PostgresqlSessions extends MysqlSessions { public boolean existsDatabase() { String statement = String.format( "SELECT datname FROM pg_catalog.pg_database " + - "WHERE datname = %s;", this.escapedDatabase()); + "WHERE datname = '%s';", this.escapedDatabase()); try (Connection conn = this.openWithoutDB(0)) { ResultSet result = conn.createStatement().executeQuery(statement); return result.next(); @@ -101,7 +101,7 @@ public class PostgresqlSessions extends MysqlSessions { " FROM pg_stat_activity " + " WHERE pg_stat_activity.datname = %s;" + "DROP DATABASE IF EXISTS %s;", - database, escapeString(database), database); + database, escapeAndWrapString(database), database); } @Override @@ -110,7 +110,7 @@ public class PostgresqlSessions extends MysqlSessions { return new URIBuilder().addParameter("loggerLevel", "OFF"); } - public static String escapeString(String value) { + public static String escapeAndWrapString(String value) { StringBuilder builder = new StringBuilder(8 + value.length()); builder.append('\''); try { diff --git a/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlStoreProvider.java b/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlStoreProvider.java index 1f6689143..f466456d8 100644 --- a/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlStoreProvider.java +++ b/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlStoreProvider.java @@ -58,8 +58,9 @@ public class PostgresqlStoreProvider extends MysqlStoreProvider { * also split range table to rangeInt, rangeFloat, * rangeLong and rangeDouble * [1.2] #633: support unique index + * [1.3] #661: reduce the storage of vertex/edge id */ - return "1.2"; + return "1.3"; } public static class PostgresqlSchemaStore extends PostgresqlStore { diff --git a/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlTable.java b/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlTable.java index 6b118ad40..4b6e7d173 100644 --- a/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlTable.java +++ b/hugegraph-postgresql/src/main/java/com/baidu/hugegraph/backend/store/postgresql/PostgresqlTable.java @@ -25,8 +25,9 @@ import java.util.List; import org.apache.logging.log4j.util.Strings; import com.baidu.hugegraph.backend.store.mysql.MysqlBackendEntry; -import com.baidu.hugegraph.backend.store.mysql.MysqlTable; import com.baidu.hugegraph.backend.store.mysql.MysqlSessions.Session; +import com.baidu.hugegraph.backend.store.mysql.MysqlTable; +import com.baidu.hugegraph.backend.store.mysql.WhereBuilder; import com.baidu.hugegraph.type.define.HugeKeys; public abstract class PostgresqlTable extends MysqlTable { @@ -38,10 +39,12 @@ public abstract class PostgresqlTable extends MysqlTable { super(table); } + @Override protected String buildDropTemplate() { return String.format("DROP TABLE IF EXISTS %s CASCADE;", this.table()); } + @Override protected String buildTruncateTemplate() { return String.format("TRUNCATE TABLE %s CASCADE;", this.table()); } @@ -112,6 +115,7 @@ public abstract class PostgresqlTable extends MysqlTable { } // Set order-by to keep results order consistence for PostgreSQL result + @Override protected String orderByKeys() { if (this.orderByKeys != null) { return this.orderByKeys; @@ -130,4 +134,24 @@ public abstract class PostgresqlTable extends MysqlTable { this.orderByKeys = select.toString(); return this.orderByKeys; } + + @Override + protected WhereBuilder newWhereBuilder(boolean startWithWhere) { + return new PgWhereBuilder(startWithWhere); + } + + private static class PgWhereBuilder extends WhereBuilder { + + public PgWhereBuilder(boolean startWithWhere) { + super(startWithWhere); + } + + @Override + protected String escapeAndWrapString(String value) { + if (value.equals("\u0000")) { + return "\'\'"; + } + return PostgresqlSessions.escapeAndWrapString(value); + } + } } diff --git a/hugegraph-rocksdb/src/main/java/com/baidu/hugegraph/backend/store/rocksdb/RocksDBStoreProvider.java b/hugegraph-rocksdb/src/main/java/com/baidu/hugegraph/backend/store/rocksdb/RocksDBStoreProvider.java index aee6b21e2..7cf6bf09f 100644 --- a/hugegraph-rocksdb/src/main/java/com/baidu/hugegraph/backend/store/rocksdb/RocksDBStoreProvider.java +++ b/hugegraph-rocksdb/src/main/java/com/baidu/hugegraph/backend/store/rocksdb/RocksDBStoreProvider.java @@ -56,7 +56,8 @@ public class RocksDBStoreProvider extends AbstractBackendStoreProvider { * also split range table to rangeInt, rangeFloat, * rangeLong and rangeDouble * [1.4] #633: support unique index + * [1.5] #680: update index element-id to bin format */ - return "1.4"; + return "1.5"; } } diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/core/EdgeLabelCoreTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/core/EdgeLabelCoreTest.java index d303e1e58..97cc5f573 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/core/EdgeLabelCoreTest.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/core/EdgeLabelCoreTest.java @@ -35,6 +35,7 @@ import com.baidu.hugegraph.schema.EdgeLabel; import com.baidu.hugegraph.schema.SchemaManager; import com.baidu.hugegraph.testutil.Assert; import com.baidu.hugegraph.type.define.Frequency; +import com.baidu.hugegraph.util.Events; public class EdgeLabelCoreTest extends SchemaCoreTest { @@ -46,15 +47,13 @@ public class EdgeLabelCoreTest extends SchemaCoreTest { .properties("name", "age", "city") .primaryKeys("name") .create(); - schema.vertexLabel("author").properties("id", "name") - .primaryKeys("id").create(); schema.vertexLabel("book").properties("id", "name") .primaryKeys("id").create(); EdgeLabel look = schema.edgeLabel("look").multiTimes() - .properties("time") - .link("person", "book") - .sortKeys("time") - .create(); + .properties("time") + .link("person", "book") + .sortKeys("time") + .create(); Assert.assertNotNull(look); Assert.assertEquals("look", look.name()); @@ -114,13 +113,11 @@ public class EdgeLabelCoreTest extends SchemaCoreTest { .properties("name", "age", "city") .primaryKeys("name") .create(); - schema.vertexLabel("author").properties("id", "name") - .primaryKeys("id").create(); schema.vertexLabel("book").properties("id", "name") .primaryKeys("id").create(); EdgeLabel look = schema.edgeLabel("look").properties("time") - .link("person", "book") - .create(); + .link("person", "book") + .create(); Assert.assertNotNull(look); Assert.assertEquals("look", look.name()); @@ -140,13 +137,11 @@ public class EdgeLabelCoreTest extends SchemaCoreTest { .properties("name", "age", "city") .primaryKeys("name") .create(); - schema.vertexLabel("author").properties("id", "name") - .primaryKeys("id").create(); schema.vertexLabel("book").properties("id", "name") .primaryKeys("id").create(); EdgeLabel look = schema.edgeLabel("look").singleTime() - .link("person", "book") - .create(); + .link("person", "book") + .create(); Assert.assertNotNull(look); Assert.assertEquals("look", look.name()); @@ -161,12 +156,6 @@ public class EdgeLabelCoreTest extends SchemaCoreTest { public void testAddEdgeLabelWithoutLink() { super.initPropertyKeys(); SchemaManager schema = graph().schema(); - schema.vertexLabel("person") - .properties("name", "age", "city") - .primaryKeys("name") - .create(); - schema.vertexLabel("author").properties("id", "name") - .primaryKeys("id").create(); Assert.assertThrows(IllegalArgumentException.class, () -> { schema.edgeLabel("look").multiTimes() @@ -184,7 +173,7 @@ public class EdgeLabelCoreTest extends SchemaCoreTest { .properties("name", "age", "city") .primaryKeys("name") .create(); - schema.vertexLabel("author").properties("id", "name") + schema.vertexLabel("book").properties("id", "name") .primaryKeys("id").create(); Assert.assertThrows(IllegalArgumentException.class, () -> { @@ -198,11 +187,7 @@ public class EdgeLabelCoreTest extends SchemaCoreTest { public void testAddEdgeLabelWithNotExistVertexLabel() { super.initPropertyKeys(); SchemaManager schema = graph().schema(); - schema.vertexLabel("person") - .properties("name", "age", "city") - .primaryKeys("name") - .create(); - schema.vertexLabel("author").properties("id", "name") + schema.vertexLabel("book").properties("id", "name") .primaryKeys("id").create(); Assert.assertThrows(IllegalArgumentException.class, () -> { @@ -303,8 +288,6 @@ public class EdgeLabelCoreTest extends SchemaCoreTest { .properties("name", "age", "city") .primaryKeys("name") .create(); - schema.vertexLabel("author").properties("id", "name") - .primaryKeys("id").create(); schema.vertexLabel("book").properties("id", "name") .primaryKeys("id").create(); EdgeLabel look = schema.edgeLabel("look") @@ -409,6 +392,89 @@ public class EdgeLabelCoreTest extends SchemaCoreTest { }); } + @Test + public void testAddEdgeLabelWithEnableLabelIndex() { + super.initPropertyKeys(); + SchemaManager schema = graph().schema(); + + schema.vertexLabel("person") + .properties("name", "age", "city") + .primaryKeys("name") + .nullableKeys("city") + .create(); + + schema.vertexLabel("book") + .properties("name") + .primaryKeys("name") + .create(); + + EdgeLabel write = schema.edgeLabel("write").link("person", "book") + .properties("time", "weight") + .enableLabelIndex(true) + .create(); + Assert.assertEquals(true, write.enableLabelIndex()); + + Vertex marko = graph().addVertex(T.label, "person", "name", "marko", + "age", 22); + Vertex java = graph().addVertex(T.label, "book", + "name", "java in action"); + Vertex hadoop = graph().addVertex(T.label, "book", + "name", "hadoop mapreduce"); + + marko.addEdge("write", java, "time", "2016-12-12", "weight", 0.3); + marko.addEdge("write", hadoop, "time", "2014-2-28", "weight", 0.5); + graph().tx().commit(); + + List edges = graph().traversal().E().hasLabel("write").toList(); + Assert.assertEquals(2, edges.size()); + } + + @Test + public void testAddEdgeLabelWithDisableeLabelIndex() { + super.initPropertyKeys(); + HugeGraph graph = graph(); + SchemaManager schema = graph.schema(); + + schema.vertexLabel("person") + .properties("name", "age", "city") + .primaryKeys("name") + .nullableKeys("city") + .create(); + + schema.vertexLabel("book") + .properties("name") + .primaryKeys("name") + .create(); + + EdgeLabel write = schema.edgeLabel("write").link("person", "book") + .properties("time", "weight") + .enableLabelIndex(false) + .create(); + Assert.assertEquals(false, write.enableLabelIndex()); + + Vertex marko = graph.addVertex(T.label, "person", "name", "marko", + "age", 22); + Vertex java = graph.addVertex(T.label, "book", + "name", "java in action"); + Vertex hadoop = graph.addVertex(T.label, "book", + "name", "hadoop mapreduce"); + + marko.addEdge("write", java, "time", "2016-12-12", "weight", 0.3); + marko.addEdge("write", hadoop, "time", "2014-2-28", "weight", 0.5); + graph.tx().commit(); + + BackendFeatures features = graph.graphTransaction().store().features(); + if (!features.supportsQueryByLabel()) { + Assert.assertThrows(NoIndexException.class, () -> { + graph.traversal().E().hasLabel("write").toList(); + }); + } else { + List edges = graph.traversal().E().hasLabel("write") + .toList(); + Assert.assertEquals(2, edges.size()); + } + } + @Test public void testAppendEdgeLabelWithUndefinedNullableKeys() { super.initPropertyKeys(); @@ -731,7 +797,7 @@ public class EdgeLabelCoreTest extends SchemaCoreTest { graph().tx().commit(); List edges = graph().traversal().E().hasLabel("write") - .has("weight", 0.5).toList(); + .has("weight", 0.5).toList(); Assert.assertNotNull(edges); Assert.assertEquals(1, edges.size()); @@ -786,7 +852,7 @@ public class EdgeLabelCoreTest extends SchemaCoreTest { graph().tx().commit(); List edges = graph().traversal().E().hasLabel("write") - .has("time", "2016-12-12").toList(); + .has("time", "2016-12-12").toList(); Assert.assertNotNull(edges); Assert.assertEquals(1, edges.size()); @@ -974,85 +1040,41 @@ public class EdgeLabelCoreTest extends SchemaCoreTest { } @Test - public void testAddEdgeLabelWithEnableLabelIndex() { + public void testListEdgeLabels() { super.initPropertyKeys(); SchemaManager schema = graph().schema(); - schema.vertexLabel("person") .properties("name", "age", "city") .primaryKeys("name") - .nullableKeys("city") .create(); - - schema.vertexLabel("book") - .properties("name") - .primaryKeys("name") - .create(); - - EdgeLabel write = schema.edgeLabel("write").link("person", "book") - .properties("time", "weight") - .enableLabelIndex(true) + schema.vertexLabel("author").properties("id", "name") + .primaryKeys("id").create(); + schema.vertexLabel("book").properties("id", "name") + .primaryKeys("id").create(); + EdgeLabel look = schema.edgeLabel("look").multiTimes() + .properties("time") + .link("person", "book") + .sortKeys("time") + .create(); + EdgeLabel write = schema.edgeLabel("write").multiTimes() + .properties("time") + .link("author", "book") + .sortKeys("time") .create(); - Assert.assertEquals(true, write.enableLabelIndex()); - Vertex marko = graph().addVertex(T.label, "person", "name", "marko", - "age", 22); - Vertex java = graph().addVertex(T.label, "book", - "name", "java in action"); - Vertex hadoop = graph().addVertex(T.label, "book", - "name", "hadoop mapreduce"); + List edgeLabels = schema.getEdgeLabels(); + Assert.assertEquals(2, edgeLabels.size()); + Assert.assertTrue(edgeLabels.contains(look)); + Assert.assertTrue(edgeLabels.contains(write)); - marko.addEdge("write", java, "time", "2016-12-12", "weight", 0.3); - marko.addEdge("write", hadoop, "time", "2014-2-28", "weight", 0.5); - graph().tx().commit(); + // clear cache + graph().schemaEventHub().call(Events.CACHE, "clear", null); - List edges = graph().traversal().E().hasLabel("write").toList(); - Assert.assertEquals(2, edges.size()); - } + Assert.assertEquals(look, schema.getEdgeLabel("look")); - @Test - public void testAddEdgeLabelWithDisableeLabelIndex() { - super.initPropertyKeys(); - HugeGraph graph = graph(); - SchemaManager schema = graph.schema(); - - schema.vertexLabel("person") - .properties("name", "age", "city") - .primaryKeys("name") - .nullableKeys("city") - .create(); - - schema.vertexLabel("book") - .properties("name") - .primaryKeys("name") - .create(); - - EdgeLabel write = schema.edgeLabel("write").link("person", "book") - .properties("time", "weight") - .enableLabelIndex(false) - .create(); - Assert.assertEquals(false, write.enableLabelIndex()); - - Vertex marko = graph.addVertex(T.label, "person", "name", "marko", - "age", 22); - Vertex java = graph.addVertex(T.label, "book", - "name", "java in action"); - Vertex hadoop = graph.addVertex(T.label, "book", - "name", "hadoop mapreduce"); - - marko.addEdge("write", java, "time", "2016-12-12", "weight", 0.3); - marko.addEdge("write", hadoop, "time", "2014-2-28", "weight", 0.5); - graph.tx().commit(); - - BackendFeatures features = graph.graphTransaction().store().features(); - if (!features.supportsQueryByLabel()) { - Assert.assertThrows(NoIndexException.class, () -> { - graph.traversal().E().hasLabel("write").toList(); - }); - } else { - List edges = graph.traversal().E().hasLabel("write") - .toList(); - Assert.assertEquals(2, edges.size()); - } + edgeLabels = schema.getEdgeLabels(); + Assert.assertEquals(2, edgeLabels.size()); + Assert.assertTrue(edgeLabels.contains(look)); + Assert.assertTrue(edgeLabels.contains(write)); } } diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/core/VertexLabelCoreTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/core/VertexLabelCoreTest.java index 70e19d43a..83d726465 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/core/VertexLabelCoreTest.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/core/VertexLabelCoreTest.java @@ -36,6 +36,7 @@ import com.baidu.hugegraph.schema.SchemaManager; import com.baidu.hugegraph.schema.VertexLabel; import com.baidu.hugegraph.testutil.Assert; import com.baidu.hugegraph.type.define.IdStrategy; +import com.baidu.hugegraph.util.Events; public class VertexLabelCoreTest extends SchemaCoreTest { @@ -45,9 +46,9 @@ public class VertexLabelCoreTest extends SchemaCoreTest { SchemaManager schema = graph().schema(); VertexLabel person = schema.vertexLabel("person") - .properties("name", "age", "city") - .primaryKeys("name") - .create(); + .properties("name", "age", "city") + .primaryKeys("name") + .create(); Assert.assertNotNull(person); Assert.assertEquals("person", person.name()); @@ -505,6 +506,59 @@ public class VertexLabelCoreTest extends SchemaCoreTest { }); } + @Test + public void testAddVertexLabelWithEnableLabelIndex() { + super.initPropertyKeys(); + SchemaManager schema = graph().schema(); + + VertexLabel person = schema.vertexLabel("person") + .properties("name", "age", "city") + .primaryKeys("name") + .nullableKeys("city") + .enableLabelIndex(true) + .create(); + Assert.assertEquals(true, person.enableLabelIndex()); + + graph().addVertex(T.label, "person", "name", "marko", "age", 18); + graph().addVertex(T.label, "person", "name", "josh", "age", 20); + graph().tx().commit(); + + List persons = graph().traversal().V() + .hasLabel("person").toList(); + Assert.assertEquals(2, persons.size()); + } + + @Test + public void testAddVertexLabelWithDisableLabelIndex() { + super.initPropertyKeys(); + HugeGraph graph = graph(); + SchemaManager schema = graph.schema(); + + VertexLabel person = schema.vertexLabel("person") + .properties("name", "age", "city") + .primaryKeys("name") + .nullableKeys("city") + .enableLabelIndex(false) + .create(); + Assert.assertEquals(false, person.enableLabelIndex()); + + graph.addVertex(T.label, "person", "name", "marko", "age", 18); + graph.addVertex(T.label, "person", "name", "josh", "age", 20); + graph().tx().commit(); + + List persons; + + BackendFeatures features = graph.graphTransaction().store().features(); + if (!features.supportsQueryByLabel()) { + Assert.assertThrows(NoIndexException.class, () -> { + graph.traversal().V().hasLabel("person").toList(); + }); + } else { + persons = graph.traversal().V().hasLabel("person").toList(); + Assert.assertEquals(2, persons.size()); + } + } + @Test public void testAppendVertexLabelWithUndefinedNullableKeys() { super.initPropertyKeys(); @@ -879,55 +933,35 @@ public class VertexLabelCoreTest extends SchemaCoreTest { } @Test - public void testAddVertexLabelWithEnableLabelIndex() { + public void testListVertexLabels() { super.initPropertyKeys(); SchemaManager schema = graph().schema(); - VertexLabel person = schema.vertexLabel("person") .properties("name", "age", "city") .primaryKeys("name") - .nullableKeys("city") - .enableLabelIndex(true) .create(); - Assert.assertEquals(true, person.enableLabelIndex()); + VertexLabel author = schema.vertexLabel("author") + .properties("id", "name") + .primaryKeys("id").create(); + VertexLabel book = schema.vertexLabel("book") + .properties("id", "name") + .primaryKeys("id").create(); - graph().addVertex(T.label, "person", "name", "marko", "age", 18); - graph().addVertex(T.label, "person", "name", "josh", "age", 20); - graph().tx().commit(); + List vertexLabels = schema.getVertexLabels(); + Assert.assertEquals(3, vertexLabels.size()); + Assert.assertTrue(vertexLabels.contains(person)); + Assert.assertTrue(vertexLabels.contains(author)); + Assert.assertTrue(vertexLabels.contains(book)); - List persons = graph().traversal().V() - .hasLabel("person").toList(); - Assert.assertEquals(2, persons.size()); - } + // clear cache + graph().schemaEventHub().call(Events.CACHE, "clear", null); - @Test - public void testAddVertexLabelWithDisableLabelIndex() { - super.initPropertyKeys(); - HugeGraph graph = graph(); - SchemaManager schema = graph.schema(); + Assert.assertEquals(person, schema.getVertexLabel("person")); - VertexLabel person = schema.vertexLabel("person") - .properties("name", "age", "city") - .primaryKeys("name") - .nullableKeys("city") - .enableLabelIndex(false) - .create(); - Assert.assertEquals(false, person.enableLabelIndex()); - - graph.addVertex(T.label, "person", "name", "marko", "age", 18); - graph.addVertex(T.label, "person", "name", "josh", "age", 20); - graph().tx().commit(); - - List persons; - - BackendFeatures features = graph.graphTransaction().store().features(); - if (!features.supportsQueryByLabel()) { - Assert.assertThrows(NoIndexException.class, () -> { - graph.traversal().V().hasLabel("person").toList(); - }); - } else { - persons = graph.traversal().V().hasLabel("person").toList(); - Assert.assertEquals(2, persons.size()); - } + vertexLabels = schema.getVertexLabels(); + Assert.assertEquals(3, vertexLabels.size()); + Assert.assertTrue(vertexLabels.contains(person)); + Assert.assertTrue(vertexLabels.contains(author)); + Assert.assertTrue(vertexLabels.contains(book)); } } diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/testutil/FakeObjects.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/testutil/FakeObjects.java index b32d43af8..a64f34dfc 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/testutil/FakeObjects.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/testutil/FakeObjects.java @@ -62,7 +62,7 @@ public class FakeObjects { private Map values; public FakeEdge(String label, Vertex outVertex, Vertex inVertex, - Object... keyValues) { + Object... keyValues) { this.label = label; this.outVertex = outVertex; this.inVertex = inVertex; diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/FakeObjects.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/FakeObjects.java index a727b325c..be4f34034 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/FakeObjects.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/FakeObjects.java @@ -20,18 +20,24 @@ package com.baidu.hugegraph.unit; import java.util.Collections; +import java.util.Date; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.PropertiesConfiguration; import org.mockito.Mockito; import com.baidu.hugegraph.HugeGraph; +import com.baidu.hugegraph.backend.id.EdgeId; import com.baidu.hugegraph.backend.id.Id; +import com.baidu.hugegraph.backend.id.IdGenerator; import com.baidu.hugegraph.config.HugeConfig; import com.baidu.hugegraph.schema.EdgeLabel; import com.baidu.hugegraph.schema.IndexLabel; import com.baidu.hugegraph.schema.PropertyKey; import com.baidu.hugegraph.schema.VertexLabel; +import com.baidu.hugegraph.structure.HugeEdge; +import com.baidu.hugegraph.structure.HugeVertex; +import com.baidu.hugegraph.testutil.Whitebox; import com.baidu.hugegraph.type.HugeType; import com.baidu.hugegraph.type.define.Cardinality; import com.baidu.hugegraph.type.define.DataType; @@ -78,6 +84,8 @@ public final class FakeObjects { PropertyKey schema = new PropertyKey(this.graph, id, name); schema.dataType(dataType); schema.cardinality(cardinality); + + Mockito.when(this.graph.propertyKey(id)).thenReturn(schema); return schema; } @@ -87,6 +95,8 @@ public final class FakeObjects { VertexLabel schema = new VertexLabel(this.graph, id, name); schema.idStrategy(idStrategy); schema.properties(properties); + + Mockito.when(this.graph.vertexLabel(id)).thenReturn(schema); return schema; } @@ -98,6 +108,8 @@ public final class FakeObjects { schema.sourceLabel(sourceLabel); schema.targetLabel(targetLabel); schema.properties(properties); + + Mockito.when(this.graph.edgeLabel(id)).thenReturn(schema); return schema; } @@ -109,6 +121,51 @@ public final class FakeObjects { schema.baseValue(baseValue); schema.indexType(indexType); schema.indexFields(fields); + + Mockito.when(this.graph.indexLabel(id)).thenReturn(schema); return schema; } + + public HugeEdge newEdge(long sourceVertexId, long targetVertexId) { + PropertyKey name = this.newPropertyKey(IdGenerator.of(1), "name"); + PropertyKey age = this.newPropertyKey(IdGenerator.of(2), "age", + DataType.INT, + Cardinality.SINGLE); + PropertyKey city = this.newPropertyKey(IdGenerator.of(3), "city"); + PropertyKey date = this.newPropertyKey(IdGenerator.of(4), "date", + DataType.DATE); + PropertyKey weight = this.newPropertyKey(IdGenerator.of(5), + "weight", DataType.DOUBLE); + + VertexLabel vl = this.newVertexLabel(IdGenerator.of(1), "person", + IdStrategy.CUSTOMIZE_NUMBER, + name.id(), age.id(), city.id()); + + EdgeLabel el = this.newEdgeLabel(IdGenerator.of(1), "knows", + Frequency.SINGLE, vl.id(), vl.id(), + date.id(), weight.id()); + + HugeVertex source = new HugeVertex(this.graph(), + IdGenerator.of(sourceVertexId), vl); + source.addProperty(name, "tom"); + source.addProperty(age, 18); + source.addProperty(city, "Beijing"); + + HugeVertex target = new HugeVertex(this.graph(), + IdGenerator.of(targetVertexId), vl); + target.addProperty(name, "cat"); + target.addProperty(age, 20); + target.addProperty(city, "Shanghai"); + + Id id = EdgeId.parse("L123456>1>>L987654"); + HugeEdge edge = new HugeEdge(this.graph(), id, el); + + Whitebox.setInternalState(edge, "sourceVertex", source); + Whitebox.setInternalState(edge, "targetVertex", target); + edge.assignId(); + edge.addProperty(date, new Date()); + edge.addProperty(weight, 0.75); + + return edge; + } } diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/UnitTestSuite.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/UnitTestSuite.java index 1a527ec71..1abb5beca 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/UnitTestSuite.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/UnitTestSuite.java @@ -26,24 +26,31 @@ import com.baidu.hugegraph.unit.cache.CacheManagerTest; import com.baidu.hugegraph.unit.cache.CachedGraphTransactionTest; import com.baidu.hugegraph.unit.cache.CachedSchemaTransactionTest; import com.baidu.hugegraph.unit.cache.RamCacheTest; +import com.baidu.hugegraph.unit.cassandra.CassandraTest; import com.baidu.hugegraph.unit.core.AnalyzerTest; import com.baidu.hugegraph.unit.core.BackendMutationTest; -import com.baidu.hugegraph.unit.core.BytesBufferTest; -import com.baidu.hugegraph.unit.core.CassandraTest; import com.baidu.hugegraph.unit.core.ConditionQueryFlattenTest; import com.baidu.hugegraph.unit.core.ConditionTest; import com.baidu.hugegraph.unit.core.DataTypeTest; import com.baidu.hugegraph.unit.core.DirectionsTest; import com.baidu.hugegraph.unit.core.EdgeIdTest; import com.baidu.hugegraph.unit.core.ExceptionTest; -import com.baidu.hugegraph.unit.core.IdTest; import com.baidu.hugegraph.unit.core.LocksTableTest; import com.baidu.hugegraph.unit.core.QueryTest; import com.baidu.hugegraph.unit.core.SecurityManagerTest; import com.baidu.hugegraph.unit.core.SerialEnumTest; +import com.baidu.hugegraph.unit.id.IdTest; +import com.baidu.hugegraph.unit.id.IdUtilTest; +import com.baidu.hugegraph.unit.mysql.MysqlUtilTest; +import com.baidu.hugegraph.unit.mysql.WhereBuilderTest; import com.baidu.hugegraph.unit.rocksdb.RocksDBCountersTest; import com.baidu.hugegraph.unit.rocksdb.RocksDBSessionsTest; -import com.baidu.hugegraph.unit.util.IdUtilTest; +import com.baidu.hugegraph.unit.serializer.BinaryBackendEntryTest; +import com.baidu.hugegraph.unit.serializer.BinaryInlineSerializerTest; +import com.baidu.hugegraph.unit.serializer.BytesBufferTest; +import com.baidu.hugegraph.unit.serializer.SerializerFactoryTest; +import com.baidu.hugegraph.unit.serializer.TableBackendEntryTest; +import com.baidu.hugegraph.unit.serializer.TextBackendEntryTest; import com.baidu.hugegraph.unit.util.JsonUtilTest; import com.baidu.hugegraph.unit.util.StringEncodingTest; import com.baidu.hugegraph.unit.util.VersionTest; @@ -61,10 +68,13 @@ import com.baidu.hugegraph.unit.util.VersionTest; DirectionsTest.class, SerialEnumTest.class, + /* id */ + IdTest.class, + IdUtilTest.class, + /* core */ LocksTableTest.class, AnalyzerTest.class, - IdTest.class, EdgeIdTest.class, BackendMutationTest.class, ConditionTest.class, @@ -72,11 +82,22 @@ import com.baidu.hugegraph.unit.util.VersionTest; QueryTest.class, SecurityManagerTest.class, ExceptionTest.class, + + /* serializer */ BytesBufferTest.class, + SerializerFactoryTest.class, + TextBackendEntryTest.class, + TableBackendEntryTest.class, + BinaryBackendEntryTest.class, + BinaryInlineSerializerTest.class, /* cassandra */ CassandraTest.class, + /* mysql */ + MysqlUtilTest.class, + WhereBuilderTest.class, + /* rocksdb */ RocksDBSessionsTest.class, RocksDBCountersTest.class, @@ -84,7 +105,6 @@ import com.baidu.hugegraph.unit.util.VersionTest; /* utils */ VersionTest.class, JsonUtilTest.class, - IdUtilTest.class, StringEncodingTest.class }) public class UnitTestSuite { diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/CassandraTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/cassandra/CassandraTest.java similarity index 99% rename from hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/CassandraTest.java rename to hugegraph-test/src/main/java/com/baidu/hugegraph/unit/cassandra/CassandraTest.java index 2851537c4..31e236909 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/CassandraTest.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/cassandra/CassandraTest.java @@ -17,7 +17,7 @@ * under the License. */ -package com.baidu.hugegraph.unit.core; +package com.baidu.hugegraph.unit.cassandra; import java.util.Map; diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/SecurityManagerTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/SecurityManagerTest.java index bc3bd9d7f..237b31564 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/SecurityManagerTest.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/SecurityManagerTest.java @@ -293,9 +293,9 @@ public class SecurityManagerTest { .job(new GremlinAPI.GremlinJob()); HugeTask task = builder.schedule(); try { - graph.taskScheduler().waitUntilTaskCompleted(task.id(), 5); + graph.taskScheduler().waitUntilTaskCompleted(task.id(), 10); } catch (TimeoutException e) { - throw new HugeException("Wait task %s timeout", e, task); + throw new HugeException("Wait for task timeout: %s", e, task); } return task.result(); } diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/IdTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/id/IdTest.java similarity index 68% rename from hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/IdTest.java rename to hugegraph-test/src/main/java/com/baidu/hugegraph/unit/id/IdTest.java index 2b8588dae..395674176 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/IdTest.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/id/IdTest.java @@ -17,10 +17,11 @@ * under the License. */ -package com.baidu.hugegraph.unit.core; +package com.baidu.hugegraph.unit.id; + +import java.nio.ByteBuffer; +import java.util.UUID; -import org.junit.After; -import org.junit.Before; import org.junit.Test; import com.baidu.hugegraph.backend.id.Id; @@ -34,16 +35,6 @@ import com.google.common.primitives.Bytes; public class IdTest extends BaseUnitTest { - @Before - public void setup() { - // pass - } - - @After - public void teardown() { - // pass - } - @Test public void testStringId() { Id id = IdGenerator.of("test-id"); @@ -144,6 +135,79 @@ public class IdTest extends BaseUnitTest { "g14RU5KBSVeGkc95JY6Q6w==", IdType.UUID)); } + @Test + public void testObjectId() { + Object object = ByteBuffer.wrap(new byte[]{1, 2}); + Object object2 = ByteBuffer.wrap(new byte[]{2, 2}); + Id id = IdGenerator.of(object); + Assert.assertEquals(IdType.UNKNOWN, id.type()); + Assert.assertEquals(object, id.asObject()); + Assert.assertEquals(object.hashCode(), id.hashCode()); + Assert.assertEquals(object.toString(), id.toString()); + Assert.assertTrue(id.equals(IdGenerator.of(object))); + Assert.assertFalse(id.equals(IdGenerator.of(object2))); + Assert.assertFalse(id.equals(object)); + + Assert.assertThrows(UnsupportedOperationException.class, () -> { + id.asString(); + }); + Assert.assertThrows(UnsupportedOperationException.class, () -> { + id.asLong(); + }); + Assert.assertThrows(UnsupportedOperationException.class, () -> { + id.asBytes(); + }); + Assert.assertThrows(UnsupportedOperationException.class, () -> { + id.compareTo(id); + }); + Assert.assertThrows(UnsupportedOperationException.class, () -> { + id.length(); + }); + } + + @Test + public void testOfObjectId() { + Object any1 = 123; + Id id1 = IdGenerator.of(any1); + Assert.assertEquals(IdType.LONG, id1.type()); + Assert.assertEquals(123L, id1.asObject()); + + Object any2 = 123L; + Id id2 = IdGenerator.of(any2); + Assert.assertEquals(id1, id2); + + Object any3 = "123"; + Id id3 = IdGenerator.of(any3); + Assert.assertEquals(IdType.STRING, id3.type()); + Assert.assertEquals("123", id3.asObject()); + + Object any4 = "12" + "3"; + Id id4 = IdGenerator.of(any4); + Assert.assertEquals(id3, id4); + + Object any5 = UUID.randomUUID(); + Id id5 = IdGenerator.of(any5); + Assert.assertEquals(IdType.UUID, id5.type()); + Assert.assertEquals(any5, id5.asObject()); + + Object any6 = UUID.fromString(any5.toString()); + Id id6 = IdGenerator.of(any6); + Assert.assertEquals(id5, id6); + + Object any7 = ByteBuffer.wrap(new byte[]{1, 2}); + Id id7 = IdGenerator.of(any7); + Assert.assertEquals(IdType.UNKNOWN, id7.type()); + Assert.assertEquals(ByteBuffer.wrap(new byte[]{1, 2}), id7.asObject()); + + Object any8 = ByteBuffer.wrap(new byte[]{1, 2}); + Id id8 = IdGenerator.of(any8); + Assert.assertEquals(id7, id8); + + Object any9 = id1; + Id id9 = IdGenerator.of(any9); + Assert.assertEquals(any9, id9); + } + @Test public void testIdType() { Assert.assertEquals(IdType.LONG, IdType.valueOfPrefix("L")); diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/util/IdUtilTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/id/IdUtilTest.java similarity index 72% rename from hugegraph-test/src/main/java/com/baidu/hugegraph/unit/util/IdUtilTest.java rename to hugegraph-test/src/main/java/com/baidu/hugegraph/unit/id/IdUtilTest.java index 1ca37919a..8a404179f 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/util/IdUtilTest.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/id/IdUtilTest.java @@ -17,7 +17,9 @@ * under the License. */ -package com.baidu.hugegraph.unit.util; +package com.baidu.hugegraph.unit.id; + +import java.nio.ByteBuffer; import org.junit.Assert; import org.junit.Test; @@ -53,6 +55,35 @@ public class IdUtilTest { Assert.assertEquals(id, IdUtil.readString("ES1111>2222>3>L4444")); } + @Test + public void testWriteReadBinString() { + Id id = IdGenerator.of(123); + ByteBuffer bytes = ByteBuffer.wrap(genBytes("087b")); + Assert.assertEquals(bytes, IdUtil.writeBinString(id)); + Assert.assertEquals(id, IdUtil.readBinString(bytes)); + + id = IdGenerator.of("123"); + bytes = ByteBuffer.wrap(genBytes("82313233")); + Assert.assertEquals(bytes, IdUtil.writeBinString(id)); + Assert.assertEquals(id, IdUtil.readBinString(bytes)); + + String uuid = "835e1153-9281-4957-8691-cf79258e90eb"; + id = IdGenerator.of(uuid, true); + bytes = ByteBuffer.wrap(genBytes("7f835e1153928149578691cf79258e90eb")); + Assert.assertEquals(bytes, IdUtil.writeBinString(id)); + Assert.assertEquals(id, IdUtil.readBinString(bytes)); + + id = EdgeId.parse("S1>2>3>L4"); + bytes = ByteBuffer.wrap(genBytes("7e803182080233ff0804")); + Assert.assertEquals(bytes, IdUtil.writeBinString(id)); + Assert.assertEquals(id, IdUtil.readBinString(bytes)); + + id = EdgeId.parse("S1111>2222>3>L4444"); + bytes = ByteBuffer.wrap(genBytes("7e8331313131821808ae33ff18115c")); + Assert.assertEquals(bytes, IdUtil.writeBinString(id)); + Assert.assertEquals(id, IdUtil.readBinString(bytes)); + } + @Test public void testWriteReadStoredString() { Id id = IdGenerator.of(123); @@ -106,4 +137,14 @@ public class IdUtilTest { Assert.assertEquals(1, IdUtil.unescape("", "", "").length); Assert.assertEquals(1, IdUtil.unescape("foo", "bar", "baz").length); } + + private byte[] genBytes(String string) { + int size = string.length() / 2; + byte[] bytes = new byte[size]; + for (int i = 0; i < size; i++) { + String b = string.substring(i * 2, i * 2 + 2); + bytes[i] = Integer.valueOf(b, 16).byteValue(); + } + return bytes; + } } diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/mysql/MysqlUtilTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/mysql/MysqlUtilTest.java new file mode 100644 index 000000000..d8fa4b089 --- /dev/null +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/mysql/MysqlUtilTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2017 HugeGraph Authors + * + * 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 com.baidu.hugegraph.unit.mysql; + +import org.junit.Test; + +import com.baidu.hugegraph.backend.store.mysql.MysqlUtil; +import com.baidu.hugegraph.testutil.Assert; +import com.baidu.hugegraph.unit.BaseUnitTest; + +public class MysqlUtilTest extends BaseUnitTest { + + @Test + public void testEscapeString() { + Assert.assertEquals("abc", MysqlUtil.escapeString("abc")); + Assert.assertEquals("abc\"", MysqlUtil.escapeString("abc\"")); + + Assert.assertEquals("can\\'t", MysqlUtil.escapeString("can't")); + Assert.assertEquals("abc\\n", MysqlUtil.escapeString("abc\n")); + Assert.assertEquals("abc\\r", MysqlUtil.escapeString("abc\r")); + Assert.assertEquals("abc\\\\", MysqlUtil.escapeString("abc\\")); + Assert.assertEquals("abc\\0", MysqlUtil.escapeString("abc\u0000")); + Assert.assertEquals("abc\\Z", MysqlUtil.escapeString("abc\u001a")); + } + + @Test + public void testEscapeAndWrapString() { + Assert.assertEquals("'abc'", MysqlUtil.escapeAndWrapString("abc")); + Assert.assertEquals("'abc\"'", MysqlUtil.escapeAndWrapString("abc\"")); + Assert.assertEquals("''", MysqlUtil.escapeAndWrapString("")); + + Assert.assertEquals("'can\\'t'", + MysqlUtil.escapeAndWrapString("can't")); + Assert.assertEquals("'abc\\n'", + MysqlUtil.escapeAndWrapString("abc\n")); + Assert.assertEquals("'abc\\r'", + MysqlUtil.escapeAndWrapString("abc\r")); + Assert.assertEquals("'abc\\\\'", + MysqlUtil.escapeAndWrapString("abc\\")); + Assert.assertEquals("'abc\\0'", + MysqlUtil.escapeAndWrapString("abc\u0000")); + Assert.assertEquals("'abc\\Z'", + MysqlUtil.escapeAndWrapString("abc\u001a")); + } +} diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/mysql/WhereBuilderTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/mysql/WhereBuilderTest.java new file mode 100644 index 000000000..b37e98e0b --- /dev/null +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/mysql/WhereBuilderTest.java @@ -0,0 +1,125 @@ +/* + * Copyright 2017 HugeGraph Authors + * + * 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 com.baidu.hugegraph.unit.mysql; + +import org.junit.Test; + +import com.baidu.hugegraph.backend.query.Condition.RelationType; +import com.baidu.hugegraph.backend.store.mysql.WhereBuilder; +import com.baidu.hugegraph.exception.NotSupportException; +import com.baidu.hugegraph.testutil.Assert; +import com.baidu.hugegraph.unit.BaseUnitTest; +import com.google.common.collect.ImmutableList; + +public class WhereBuilderTest extends BaseUnitTest { + + @Test + public void testRelation() { + WhereBuilder where = new WhereBuilder(); + where.relation("key1", RelationType.EQ, "value1"); + Assert.assertEquals(" WHERE key1='value1'", where.build().toString()); + Assert.assertEquals(" WHERE key1='value1'", where.toString()); + + where = new WhereBuilder(false); + where.relation("key1", RelationType.EQ, "value1"); + Assert.assertEquals(" key1='value1'", where.build().toString()); + Assert.assertEquals(" key1='value1'", where.toString()); + + where.and().relation("key2", RelationType.EQ, "value2"); + Assert.assertEquals(" key1='value1' AND key2='value2'", + where.toString()); + + where = new WhereBuilder(false); + where.relation("key1", RelationType.NEQ, "value1"); + Assert.assertEquals(" key1!='value1'", where.toString()); + + where = new WhereBuilder(false); + where.relation("key1", RelationType.GT, "value1"); + Assert.assertEquals(" key1>'value1'", where.toString()); + + where = new WhereBuilder(false); + where.relation("key1", RelationType.GTE, "value1"); + Assert.assertEquals(" key1>='value1'", where.toString()); + + where = new WhereBuilder(false); + where.relation("key1", RelationType.LT, "value1"); + Assert.assertEquals(" key1<'value1'", where.toString()); + + where = new WhereBuilder(false); + where.relation("key1", RelationType.LTE, "value1"); + Assert.assertEquals(" key1<='value1'", where.toString()); + + where = new WhereBuilder(false); + where.relation("key1", RelationType.IN, ImmutableList.of("v1", "v2")); + Assert.assertEquals(" key1 IN ('v1', 'v2')", where.toString()); + + Assert.assertThrows(NotSupportException.class, () -> { + new WhereBuilder().relation("k", RelationType.CONTAINS_KEY, "v"); + }); + Assert.assertThrows(NotSupportException.class, () -> { + new WhereBuilder().relation("k", RelationType.CONTAINS_VALUE, "v"); + }); + Assert.assertThrows(NotSupportException.class, () -> { + new WhereBuilder().relation("k", RelationType.NOT_IN, "v"); + }); + Assert.assertThrows(NotSupportException.class, () -> { + new WhereBuilder().relation("k", RelationType.TEXT_CONTAINS, "v"); + }); + Assert.assertThrows(NotSupportException.class, () -> { + new WhereBuilder().relation("k", RelationType.SCAN, "v"); + }); + } + + @Test + public void testAnd() { + WhereBuilder where = new WhereBuilder(false); + where.and(ImmutableList.of("k1", "k2"), ImmutableList.of("v1", "v2")); + Assert.assertEquals(" k1='v1' AND k2='v2'", where.toString()); + + where = new WhereBuilder(false); + where.and(ImmutableList.of("k1", "k2"), "!=", + ImmutableList.of("v1", "v2")); + Assert.assertEquals(" k1!='v1' AND k2!='v2'", where.toString()); + + where = new WhereBuilder(false); + where.and(ImmutableList.of("k1", "k2", "k3"), + ImmutableList.of("=", "!=", ">"), + ImmutableList.of("v1", "v2", 3)); + Assert.assertEquals(" k1='v1' AND k2!='v2' AND k3>3", where.toString()); + + where = new WhereBuilder(false); + where.and(ImmutableList.of("k1", "k2"), "="); + Assert.assertEquals(" k1=? AND k2=?", where.toString()); + } + + @Test + public void testIn() { + WhereBuilder where = new WhereBuilder(false); + where.in("key", ImmutableList.of("v1", "v2", "v3")); + Assert.assertEquals(" key IN ('v1', 'v2', 'v3')", where.toString()); + } + + @Test + public void testGt() { + WhereBuilder where = new WhereBuilder(false); + where.gte(ImmutableList.of("k1", "k2"), ImmutableList.of("v1", "v2")); + Assert.assertEquals(" (k1, k2) >= ('v1', 'v2')", where.toString()); + } +} diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/BinaryBackendEntryTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/BinaryBackendEntryTest.java new file mode 100644 index 000000000..8674f944a --- /dev/null +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/BinaryBackendEntryTest.java @@ -0,0 +1,115 @@ +/* + * Copyright 2017 HugeGraph Authors + * + * 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 com.baidu.hugegraph.unit.serializer; + +import org.junit.Test; + +import com.baidu.hugegraph.backend.serializer.BinaryBackendEntry; +import com.baidu.hugegraph.backend.store.BackendEntry.BackendColumn; +import com.baidu.hugegraph.testutil.Assert; +import com.baidu.hugegraph.type.HugeType; +import com.baidu.hugegraph.unit.BaseUnitTest; +import com.google.common.collect.ImmutableList; + +public class BinaryBackendEntryTest extends BaseUnitTest { + + @Test + public void testColumns() { + BinaryBackendEntry entry = new BinaryBackendEntry(HugeType.VERTEX, + new byte[]{1, 2}); + BackendColumn col = BackendColumn.of(new byte[]{1, 2}, + new byte[]{3, 4}); + + entry.columns(ImmutableList.of(col)); + Assert.assertEquals(1, entry.columnsSize()); + Assert.assertEquals(ImmutableList.of(col), entry.columns()); + + entry.columns(ImmutableList.of(col, col)); + Assert.assertEquals(3, entry.columnsSize()); + Assert.assertEquals(ImmutableList.of(col, col, col), entry.columns()); + } + + @Test + public void testClear() { + BinaryBackendEntry entry = new BinaryBackendEntry(HugeType.VERTEX, + new byte[]{1, 2}); + BackendColumn col = BackendColumn.of(new byte[]{1, 2}, + new byte[]{3, 4}); + + entry.column(col); + Assert.assertEquals(1, entry.columnsSize()); + Assert.assertEquals(ImmutableList.of(col), entry.columns()); + + entry.clear(); + Assert.assertEquals(0, entry.columnsSize()); + Assert.assertEquals(ImmutableList.of(), entry.columns()); + } + + @Test + public void testMerge() { + BinaryBackendEntry entry = new BinaryBackendEntry(HugeType.VERTEX, + new byte[]{1, 2}); + BinaryBackendEntry entry2 = new BinaryBackendEntry(HugeType.VERTEX, + new byte[]{2, 2}); + BackendColumn col = BackendColumn.of(new byte[]{1, 2}, + new byte[]{3, 4}); + BackendColumn col2 = BackendColumn.of(new byte[]{5, 6}, + new byte[]{7, 8}); + + entry.column(col); + entry2.column(col2); + Assert.assertEquals(1, entry.columnsSize()); + Assert.assertEquals(ImmutableList.of(col), entry.columns()); + + entry.merge(entry2); + Assert.assertEquals(2, entry.columnsSize()); + Assert.assertEquals(ImmutableList.of(col, col2), entry.columns()); + } + + @Test + public void testEquals() { + BinaryBackendEntry entry = new BinaryBackendEntry(HugeType.VERTEX, + new byte[]{1, 2}); + BinaryBackendEntry entry2 = new BinaryBackendEntry(HugeType.VERTEX, + new byte[]{2, 2}); + BinaryBackendEntry entry3 = new BinaryBackendEntry(HugeType.VERTEX, + new byte[]{1, 2}); + BinaryBackendEntry entry4 = new BinaryBackendEntry(HugeType.VERTEX, + new byte[]{1, 2}); + BinaryBackendEntry entry5 = new BinaryBackendEntry(HugeType.VERTEX, + new byte[]{1, 2}); + BackendColumn col = BackendColumn.of(new byte[]{1, 2}, + new byte[]{3, 4}); + BackendColumn col2 = BackendColumn.of(new byte[]{5, 6}, + new byte[]{7, 8}); + + entry.column(col); + entry2.column(col2); + entry3.column(col2); + entry4.column(col); + entry4.column(col2); + entry5.column(col); + + Assert.assertNotEquals(entry, entry2); + Assert.assertNotEquals(entry, entry3); + Assert.assertNotEquals(entry, entry4); + Assert.assertEquals(entry, entry5); + } +} diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/BinaryInlineSerializerTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/BinaryInlineSerializerTest.java new file mode 100644 index 000000000..bd7f7a5f0 --- /dev/null +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/BinaryInlineSerializerTest.java @@ -0,0 +1,82 @@ +/* + * Copyright 2017 HugeGraph Authors + * + * 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 com.baidu.hugegraph.unit.serializer; + +import org.junit.Test; + +import com.baidu.hugegraph.backend.serializer.BinaryInlineSerializer; +import com.baidu.hugegraph.backend.store.BackendEntry; +import com.baidu.hugegraph.structure.HugeEdge; +import com.baidu.hugegraph.structure.HugeVertex; +import com.baidu.hugegraph.testutil.Assert; +import com.baidu.hugegraph.testutil.Whitebox; +import com.baidu.hugegraph.unit.BaseUnitTest; +import com.baidu.hugegraph.unit.FakeObjects; + +public class BinaryInlineSerializerTest extends BaseUnitTest { + + @Test + public void testVertex() { + BinaryInlineSerializer ser = new BinaryInlineSerializer(); + HugeEdge edge = new FakeObjects().newEdge(123, 456); + + BackendEntry entry1 = ser.writeVertex(edge.sourceVertex()); + HugeVertex vertex1 = ser.readVertex(edge.graph(), entry1); + Assert.assertEquals(edge.sourceVertex(), vertex1); + Assert.assertEquals(edge.sourceVertex().getProperties(), + vertex1.getProperties()); + + BackendEntry entry2 = ser.writeVertex(edge.targetVertex()); + HugeVertex vertex2 = ser.readVertex(edge.graph(), entry2); + Assert.assertEquals(edge.targetVertex(), vertex2); + Assert.assertEquals(edge.targetVertex().getProperties(), + vertex2.getProperties()); + + Whitebox.setInternalState(vertex2, "removed", true); + Assert.assertTrue(vertex2.removed()); + BackendEntry entry3 = ser.writeVertex(vertex2); + Assert.assertEquals(0, entry3.columnsSize()); + + Assert.assertNull(ser.readVertex(edge.graph(), null)); + } + + @Test + public void testEdge() { + BinaryInlineSerializer ser = new BinaryInlineSerializer(); + + FakeObjects objects = new FakeObjects(); + HugeEdge edge1 = objects.newEdge(123, 456); + HugeEdge edge2 = objects.newEdge(147, 789); + + BackendEntry entry1 = ser.writeEdge(edge1); + HugeVertex vertex1 = ser.readVertex(edge1.graph(), entry1); + Assert.assertEquals(1, vertex1.getEdges().size()); + HugeEdge edge = vertex1.getEdges().iterator().next(); + Assert.assertEquals(edge1, edge); + Assert.assertEquals(edge1.getProperties(), edge.getProperties()); + + BackendEntry entry2 = ser.writeEdge(edge2); + HugeVertex vertex2 = ser.readVertex(edge1.graph(), entry2); + Assert.assertEquals(1, vertex2.getEdges().size()); + edge = vertex2.getEdges().iterator().next(); + Assert.assertEquals(edge2, edge); + Assert.assertEquals(edge2.getProperties(), edge.getProperties()); + } +} diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/BytesBufferTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/BytesBufferTest.java similarity index 99% rename from hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/BytesBufferTest.java rename to hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/BytesBufferTest.java index dc62d9cde..2d0ad9d19 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/BytesBufferTest.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/BytesBufferTest.java @@ -17,7 +17,7 @@ * under the License. */ -package com.baidu.hugegraph.unit.core; +package com.baidu.hugegraph.unit.serializer; import java.awt.Point; import java.util.Arrays; diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/SerializerFactoryTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/SerializerFactoryTest.java new file mode 100644 index 000000000..3898eee8d --- /dev/null +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/SerializerFactoryTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 2017 HugeGraph Authors + * + * 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 com.baidu.hugegraph.unit.serializer; + +import org.junit.Test; + +import com.baidu.hugegraph.backend.BackendException; +import com.baidu.hugegraph.backend.serializer.AbstractSerializer; +import com.baidu.hugegraph.backend.serializer.BinaryInlineSerializer; +import com.baidu.hugegraph.backend.serializer.BinarySerializer; +import com.baidu.hugegraph.backend.serializer.SerializerFactory; +import com.baidu.hugegraph.backend.serializer.TextSerializer; +import com.baidu.hugegraph.testutil.Assert; +import com.baidu.hugegraph.unit.BaseUnitTest; + +public class SerializerFactoryTest extends BaseUnitTest { + + @Test + public void testSerializer() { + AbstractSerializer serializer = SerializerFactory.serializer("text"); + Assert.assertEquals(TextSerializer.class, serializer.getClass()); + + serializer = SerializerFactory.serializer("binary"); + Assert.assertEquals(BinarySerializer.class, serializer.getClass()); + + serializer = SerializerFactory.serializer("binaryinline"); + Assert.assertEquals(BinaryInlineSerializer.class, + serializer.getClass()); + + Assert.assertThrows(BackendException.class, () -> { + SerializerFactory.serializer("invalid"); + }, e -> { + Assert.assertTrue(e.getMessage().contains( + "Not exists serializer:")); + }); + } + + @Test + public void testRegister() { + SerializerFactory.register("fake", FakeSerializer.class.getName()); + Assert.assertEquals(FakeSerializer.class, + SerializerFactory.serializer("fake").getClass()); + + Assert.assertThrows(BackendException.class, () -> { + // exist + SerializerFactory.register("fake", FakeSerializer.class.getName()); + }, e -> { + Assert.assertTrue(e.getMessage().contains("Exists serializer:")); + }); + + Assert.assertThrows(BackendException.class, () -> { + // invalid class + SerializerFactory.register("fake", "com.baidu.hugegraph.Invalid"); + }, e -> { + Assert.assertTrue(e.getMessage().contains("Invalid class:")); + }); + + Assert.assertThrows(BackendException.class, () -> { + // subclass + SerializerFactory.register("fake", "com.baidu.hugegraph.HugeGraph"); + }, e -> { + Assert.assertTrue(e.getMessage().contains( + "Class is not a subclass of class")); + }); + } + + public static class FakeSerializer extends BinarySerializer { + + public FakeSerializer() { + super(true, true); + } + } +} diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/TableBackendEntryTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/TableBackendEntryTest.java new file mode 100644 index 000000000..8837692af --- /dev/null +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/TableBackendEntryTest.java @@ -0,0 +1,194 @@ +/* + * Copyright 2017 HugeGraph Authors + * + * 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 com.baidu.hugegraph.unit.serializer; + +import org.apache.commons.lang3.NotImplementedException; +import org.junit.Test; + +import com.baidu.hugegraph.backend.id.Id; +import com.baidu.hugegraph.backend.id.IdGenerator; +import com.baidu.hugegraph.backend.serializer.TableBackendEntry; +import com.baidu.hugegraph.backend.store.BackendEntry.BackendColumn; +import com.baidu.hugegraph.testutil.Assert; +import com.baidu.hugegraph.type.HugeType; +import com.baidu.hugegraph.type.define.Cardinality; +import com.baidu.hugegraph.type.define.HugeKeys; +import com.baidu.hugegraph.unit.BaseUnitTest; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +public class TableBackendEntryTest extends BaseUnitTest { + + @Test + public void testType() { + Id id = IdGenerator.of(1L); + TableBackendEntry entry = new TableBackendEntry(id); + Assert.assertNull(entry.type()); + Assert.assertEquals(id, entry.id()); + + entry.type(HugeType.VERTEX); + Assert.assertEquals(HugeType.VERTEX, entry.type()); + } + + @Test + public void testId() { + TableBackendEntry entry = new TableBackendEntry(HugeType.VERTEX); + Assert.assertNull(entry.id()); + + Id id = IdGenerator.of(1L); + entry.id(id); + Assert.assertEquals(HugeType.VERTEX, entry.type()); + Assert.assertEquals(id, entry.id()); + + Assert.assertNull(entry.subId()); + entry.subId(id); + Assert.assertEquals(id, entry.subId()); + } + + @Test + public void testSelfChanged() { + TableBackendEntry entry = new TableBackendEntry(HugeType.VERTEX); + Assert.assertTrue(entry.selfChanged()); + + entry.selfChanged(false); + Assert.assertFalse(entry.selfChanged()); + } + + @Test + public void testColumn() { + TableBackendEntry entry = new TableBackendEntry(HugeType.VERTEX, + IdGenerator.of(1L)); + entry.column(HugeKeys.ID, "v1"); + Assert.assertEquals("v1", entry.column(HugeKeys.ID)); + Assert.assertEquals("TableBackendEntry{Row{type=VERTEX, id=1, " + + "columns={ID=v1}}, sub-rows: []}", + entry.toString()); + + entry.column(HugeKeys.ID, "v2"); + Assert.assertEquals("v2", entry.column(HugeKeys.ID)); + Assert.assertEquals("TableBackendEntry{Row{type=VERTEX, id=1, " + + "columns={ID=v2}}, sub-rows: []}", + entry.toString()); + + entry.column(HugeKeys.NAME, "tom"); + Assert.assertEquals("tom", entry.column(HugeKeys.NAME)); + Assert.assertEquals("v2", entry.column(HugeKeys.ID)); + } + + @Test + public void testColumnOfMap() { + TableBackendEntry entry = new TableBackendEntry(HugeType.VERTEX); + entry.column(HugeKeys.PROPERTIES, "k1", "v1"); + Assert.assertEquals(ImmutableMap.of("k1", "v1"), + entry.column(HugeKeys.PROPERTIES)); + + entry.column(HugeKeys.PROPERTIES, "k2", "v2"); + Assert.assertEquals(ImmutableMap.of("k1", "v1", "k2", "v2"), + entry.column(HugeKeys.PROPERTIES)); + + entry.column(HugeKeys.PROPERTIES, "k3", "v3"); + Assert.assertEquals(ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3"), + entry.column(HugeKeys.PROPERTIES)); + + entry.column(HugeKeys.PROPERTIES, "k1", "v0"); + Assert.assertEquals(ImmutableMap.of("k1", "v0", "k2", "v2", "k3", "v3"), + entry.column(HugeKeys.PROPERTIES)); + } + + @Test + public void testColumnWithCardinalitySingle() { + TableBackendEntry entry = new TableBackendEntry(HugeType.VERTEX); + entry.column(HugeKeys.ID, "v1", Cardinality.SINGLE); + Assert.assertEquals("v1", entry.column(HugeKeys.ID)); + + entry.column(HugeKeys.ID, "v2", Cardinality.SINGLE); + Assert.assertEquals("v2", entry.column(HugeKeys.ID)); + + Assert.assertThrows(ClassCastException.class, () -> { + entry.column(HugeKeys.ID, "v3", Cardinality.SET); + }); + } + + @Test + public void testColumnWithCardinalityList() { + TableBackendEntry entry = new TableBackendEntry(HugeType.VERTEX); + entry.column(HugeKeys.PROPERTIES, "v1", Cardinality.LIST); + Assert.assertEquals(ImmutableList.of("v1"), + entry.column(HugeKeys.PROPERTIES)); + + entry.column(HugeKeys.PROPERTIES, "v2", Cardinality.LIST); + Assert.assertEquals(ImmutableList.of("v1", "v2"), + entry.column(HugeKeys.PROPERTIES)); + + entry.column(HugeKeys.PROPERTIES, "v3", Cardinality.LIST); + Assert.assertEquals(ImmutableList.of("v1", "v2", "v3"), + entry.column(HugeKeys.PROPERTIES)); + + entry.column(HugeKeys.PROPERTIES, "v2", Cardinality.LIST); + Assert.assertEquals(ImmutableList.of("v1", "v2", "v3", "v2"), + entry.column(HugeKeys.PROPERTIES)); + } + + @Test + public void testColumnWithCardinalitySet() { + TableBackendEntry entry = new TableBackendEntry(HugeType.VERTEX); + entry.column(HugeKeys.PROPERTIES, "v1", Cardinality.SET); + Assert.assertEquals(ImmutableSet.of("v1"), + entry.column(HugeKeys.PROPERTIES)); + + entry.column(HugeKeys.PROPERTIES, "v2", Cardinality.SET); + Assert.assertEquals(ImmutableSet.of("v1", "v2"), + entry.column(HugeKeys.PROPERTIES)); + + entry.column(HugeKeys.PROPERTIES, "v3", Cardinality.SET); + Assert.assertEquals(ImmutableSet.of("v1", "v2", "v3"), + entry.column(HugeKeys.PROPERTIES)); + + entry.column(HugeKeys.PROPERTIES, "v2", Cardinality.SET); + Assert.assertEquals(ImmutableSet.of("v1", "v2", "v3"), + entry.column(HugeKeys.PROPERTIES)); + } + + @Test + public void testNotImplemented() { + TableBackendEntry entry = new TableBackendEntry(HugeType.VERTEX); + BackendColumn col = BackendColumn.of(new byte[]{1}, new byte[]{12}); + + Assert.assertThrows(NotImplementedException.class, () -> { + entry.columnsSize(); + }); + Assert.assertThrows(NotImplementedException.class, () -> { + entry.columns(); + }); + Assert.assertThrows(NotImplementedException.class, () -> { + entry.columns(ImmutableList.of(col)); + }); + Assert.assertThrows(NotImplementedException.class, () -> { + entry.columns(col); + }); + Assert.assertThrows(NotImplementedException.class, () -> { + entry.merge(entry); + }); + Assert.assertThrows(NotImplementedException.class, () -> { + entry.clear(); + }); + } +} diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/TextBackendEntryTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/TextBackendEntryTest.java new file mode 100644 index 000000000..9edfba0ca --- /dev/null +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/serializer/TextBackendEntryTest.java @@ -0,0 +1,96 @@ +/* + * Copyright 2017 HugeGraph Authors + * + * 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 com.baidu.hugegraph.unit.serializer; + +import org.junit.Test; + +import com.baidu.hugegraph.backend.id.IdGenerator; +import com.baidu.hugegraph.backend.serializer.TextBackendEntry; +import com.baidu.hugegraph.backend.store.BackendEntry.BackendColumn; +import com.baidu.hugegraph.testutil.Assert; +import com.baidu.hugegraph.type.HugeType; +import com.baidu.hugegraph.type.define.HugeKeys; +import com.baidu.hugegraph.unit.BaseUnitTest; +import com.google.common.collect.ImmutableList; + +public class TextBackendEntryTest extends BaseUnitTest { + + @Test + public void testColumns() { + TextBackendEntry entry = new TextBackendEntry(HugeType.VERTEX, + IdGenerator.of(1)); + entry.column(HugeKeys.ID, "1"); + entry.column(HugeKeys.NAME, "tom"); + + BackendColumn col1 = BackendColumn.of(new byte[]{'i', 'd'}, + new byte[]{'1'}); + BackendColumn col2 = BackendColumn.of(new byte[]{'n', 'a', 'm', 'e'}, + new byte[]{'t', 'o', 'm'}); + + Assert.assertEquals(2, entry.columnsSize()); + Assert.assertEquals(ImmutableList.of(col1, col2), + entry.columns()); + } + + @Test + public void testCopy() { + TextBackendEntry entry = new TextBackendEntry(HugeType.VERTEX, + IdGenerator.of(1)); + entry.column(HugeKeys.ID, "1"); + entry.column(HugeKeys.NAME, "tom"); + Assert.assertEquals(2, entry.columnsSize()); + + TextBackendEntry entry2 = entry.copy(); + Assert.assertEquals(2, entry2.columnsSize()); + Assert.assertEquals("1", entry2.column(HugeKeys.ID)); + Assert.assertEquals("tom", entry2.column(HugeKeys.NAME)); + + entry2.clear(); + Assert.assertEquals(0, entry2.columnsSize()); + + Assert.assertEquals(2, entry.columnsSize()); + } + + @Test + public void testEquals() { + TextBackendEntry entry = new TextBackendEntry(HugeType.VERTEX, + IdGenerator.of(1)); + TextBackendEntry entry2 = new TextBackendEntry(HugeType.VERTEX, + IdGenerator.of(2)); + TextBackendEntry entry3 = new TextBackendEntry(HugeType.VERTEX, + IdGenerator.of(1)); + TextBackendEntry entry4 = new TextBackendEntry(HugeType.VERTEX, + IdGenerator.of(1)); + TextBackendEntry entry5 = new TextBackendEntry(HugeType.VERTEX, + IdGenerator.of(1)); + entry.column(HugeKeys.NAME, "tom"); + entry2.column(HugeKeys.NAME, "tom"); + entry3.column(HugeKeys.NAME, "tom2"); + entry4.column(HugeKeys.NAME, "tom"); + entry4.column(HugeKeys.LABEL, "person"); + entry5.column(HugeKeys.NAME, "tom"); + + Assert.assertNotEquals(entry, entry2); + Assert.assertNotEquals(entry, entry3); + Assert.assertNotEquals(entry, entry4); + Assert.assertNotEquals(entry4, entry); + Assert.assertEquals(entry, entry5); + } +} diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/util/JsonUtilTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/util/JsonUtilTest.java index 54299b123..f954085fb 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/util/JsonUtilTest.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/util/JsonUtilTest.java @@ -24,8 +24,6 @@ import java.util.List; import java.util.Map; import org.apache.tinkerpop.shaded.jackson.core.type.TypeReference; -import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; @@ -59,16 +57,6 @@ import com.google.common.collect.ImmutableMap; public class JsonUtilTest extends BaseUnitTest { - @Before - public void setup() { - // pass - } - - @After - public void teardown() { - // pass - } - @Test public void testSerializeStringId() { Id id = IdGenerator.of("123456"); @@ -295,7 +283,7 @@ public class JsonUtilTest extends BaseUnitTest { @Test public void testDeserializeList() { String json = "[\"1\", \"2\", \"3\"]"; - TypeReference typeRef = new TypeReference>() {}; + TypeReference typeRef = new TypeReference>() {}; Assert.assertEquals(ImmutableList.of(1, 2, 3), JsonUtil.fromJson(json, typeRef)); }