hugraph對象為百度的開源圖數(shù)據(jù)庫,實現(xiàn)了Tinkerpop框架,本系列解讀 hugegraph-core 的開源代碼,加深圖數(shù)據(jù)的理解。
hugeraph項目 提供了 api 功能桶良,用戶可以調(diào)用 api 添加節(jié)點,本文就以 這個 增加節(jié)點的api為起點沮翔,一步一步講解 hugegraph是如何實現(xiàn)的陨帆。
addVertex 作為 api 的入口
@POST
@Timed
@Status(Status.CREATED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String create(@Context GraphManager manager,
@PathParam("graph") String graph,
JsonVertex jsonVertex) {
LOG.debug("Graph [{}] create vertex: {}", graph, jsonVertex);
checkCreatingBody(jsonVertex);
HugeGraph g = graph(manager, graph);
Vertex vertex = commit(g, () -> g.addVertex(jsonVertex.properties()));
return manager.serializer(g).writeVertex(vertex);
}
可以看到 所有的起點就是需要 創(chuàng)建一個 HugeGraph對象,Hugegraph 對象里面 包含了 addVertex 方法采蚀。
本文就重點講解 HugeGraph是如何創(chuàng)建的
graph(manager, graph)
public static HugeGraph graph(GraphManager manager, String graph) {
HugeGraph g = manager.graph(graph);
if (g == null) {
throw new NotFoundException(String.format(
"Graph '%s' does not exist", graph));
}
return g;
}
實際是使用graphManager的map疲牵,根據(jù) graph名字獲取對象。
那么graphManager 是關(guān)鍵對象
構(gòu)建GraphManager
hugegraph 使用GraphManager直接獲取HugeGraph對象
對于GraphManger對象
private final Map<String, Graph> graphs;
private final HugeAuthenticator authenticator;
public GraphManager(HugeConfig conf) {
this.graphs = new ConcurrentHashMap<>();
if (conf.get(ServerOptions.AUTHENTICATOR).isEmpty()) {
this.authenticator = null;
} else {
this.authenticator = HugeAuthenticator.loadAuthenticator(conf);
}
this.loadGraphs(conf.getMap(ServerOptions.GRAPHS));
this.checkBackendVersionOrExit();
this.restoreUncompletedTasks();
this.addMetrics(conf);
}
由于hugegraph是支持多圖的搏存,所有有GrappManager保存一個 多圖的引用map瑰步。
在構(gòu)建GraphManager對象的時候
最重要的一步是
this.loadGraphs(conf.getMap(ServerOptions.GRAPHS));
private void loadGraph(String name, String path) {
final Graph graph = GraphFactory.open(path);
this.graphs.put(name, graph);
LOG.info("Graph '{}' was successfully configured via '{}'", name, path);
if (this.requireAuthentication() &&
!(graph instanceof HugeGraphAuthProxy)) {
LOG.warn("You may need to support access control for '{}' with {}",
path, HugeFactoryAuthProxy.GRAPH_FACTORY);
}
}
可以看到 關(guān)鍵的一句 final Graph graph = GraphFactory.open(path);
這個 Graph 和GraphFactory 都是 tinkerpop的標(biāo)準(zhǔn)接口。
path參數(shù)就是 我們的圖的配置文件璧眠,默認(rèn)是 conf/hugegraph.properties.
在配置文件中 (conf/hugegraph.propreties)我們有一行:
gremlin.graph=com.baidu.hugegraph.HugeFactory
這一行指定了具體創(chuàng)建圖的 工廠類缩焦,查看 HugeFactory 的open方法:
public static synchronized HugeGraph open(Configuration config) {
HugeConfig conf = new HugeConfig(config);
String name = conf.get(CoreOptions.STORE);
HugeGraph graph = graphs.get(name);
if (graph == null || graph.closed()) {
graph = new HugeGraph(conf);
graphs.put(name, graph);
} else {
String backend = conf.get(CoreOptions.BACKEND);
E.checkState(backend.equals(graph.backend()),
"Graph name '%s' has been used by backend '%s'",
name, graph.backend());
}
return graph;
}
這里面 調(diào)用了 HugeGraph的 構(gòu)造方法
graph = new HugeGraph(conf);
下面看看 HugeGraph 到底是如何構(gòu)造的?
構(gòu)建 HugeGraph 對象
public HugeGraph(HugeConfig configuration) {
this.configuration = configuration;
this.schemaEventHub = new EventHub("schema");
this.indexEventHub = new EventHub("index");
final int limit = configuration.get(CoreOptions.RATE_LIMIT);
this.rateLimiter = limit > 0 ? RateLimiter.create(limit) : null;
this.taskManager = TaskManager.instance();
this.features = new HugeFeatures(this, true);
this.name = configuration.get(CoreOptions.STORE);
this.closed = false;
this.mode = GraphMode.NONE;
LockUtil.init(this.name);
try {
this.storeProvider = this.loadStoreProvider();
} catch (BackendException e) {
String message = "Failed to init backend store";
LOG.error("{}: {}", message, e.getMessage());
throw new HugeException(message);
}
this.tx = new TinkerpopTransaction(this);
this.taskManager.addScheduler(this);
this.variables = null;
}
- rateLimiter 設(shè)置hugegraph 增刪改查的節(jié)點速度
- features 設(shè)置hugegraph 對于tinkerpop的特性支持责静,目前hugegraph是對tinkerpop的一個標(biāo)準(zhǔn)子集
- LockUtil.init(this.name) 初始化圖上的鎖袁滥,對于圖的操作有很多需要異步加鎖的地方,鎖機制后面專門講解
- this.storeProvider = this.loadStoreProvider() 加載 存儲模塊灾螃。hugegraph支持多種存儲終端题翻,在這里根據(jù)配置信息初始化存儲終端
- 設(shè)置對應(yīng)的事務(wù)對象 this.tx = new TinkerpopTransaction(this);
初始化 storeProvider
private BackendStoreProvider loadStoreProvider() {
String backend = this.configuration.get(CoreOptions.BACKEND);
LOG.info("Opening backend store '{}' for graph '{}'",
backend, this.name);
return BackendProviderFactory.open(backend, this.name);
}
調(diào)用 BackendProviderFactory.open(backend, this.name) 方法
public static BackendStoreProvider open(String backend, String graph) {
if (InMemoryDBStoreProvider.matchType(backend)) {
return InMemoryDBStoreProvider.instance(graph);
}
Class<? extends BackendStoreProvider> clazz = providers.get(backend);
BackendException.check(clazz != null,
"Not exists BackendStoreProvider: %s", backend);
assert BackendStoreProvider.class.isAssignableFrom(clazz);
BackendStoreProvider instance = null;
try {
instance = clazz.newInstance();
} catch (Exception e) {
throw new BackendException(e);
}
BackendException.check(backend.equalsIgnoreCase(instance.type()),
"BackendStoreProvider with type '%s' " +
"can't be opened by key '%s'",
instance.type(), backend);
instance.open(graph);
return instance;
}
使用反射的方法 獲取 BackendStoreProvider 對象, 對于 hugegraph 提供了多個 provider腰鬼,
根據(jù)配置信息獲取具體的Provider嵌赠。
看下在哪里配置了不同的provider?
hugegraph 有一個子module熄赡, hugegraph-dist姜挺, 這里面有相應(yīng)的配置信息
下面代碼來自 RegisterUtil
public static void registerCassandra() {
// Register config
OptionSpace.register("cassandra",
"com.baidu.hugegraph.backend.store.cassandra.CassandraOptions");
// Register serializer
SerializerFactory.register("cassandra",
"com.baidu.hugegraph.backend.store.cassandra.CassandraSerializer");
// Register backend
BackendProviderFactory.register("cassandra",
"com.baidu.hugegraph.backend.store.cassandra.CassandraStoreProvider");
}
初始化 transcation
this.tx = new TinkerpopTransaction(this);
TinkerpopTransaction 繼承自 tinkerpop 的抽象類 AbstractThreadLocalTransaction ,
該抽象類實現(xiàn)了 tinkerpop的 Transaction 接口彼硫,定了以tinkerpop的事務(wù)標(biāo)準(zhǔn)炊豪。
從TinkerpopTransaction 來看凌箕, hugegraph 定義了 GraphTransaction 和schemaTransaction
private class TinkerpopTransaction extends AbstractThreadLocalTransaction {
private AtomicInteger refs;
private ThreadLocal<Boolean> opened;
// Backend transactions
private ThreadLocal<GraphTransaction> graphTransaction;
private ThreadLocal<SchemaTransaction> schemaTransaction;
private SchemaTransaction schemaTransaction() {
/*
* NOTE: this method may be called even tx is not opened,
* the reason is for reusing backend tx.
* so we don't call this.verifyOpened() here.
*/
SchemaTransaction schemaTx = this.schemaTransaction.get();
if (schemaTx == null) {
schemaTx = openSchemaTransaction();
this.schemaTransaction.set(schemaTx);
}
return schemaTx;
}
private GraphTransaction graphTransaction() {
/*
* NOTE: this method may be called even tx is not opened,
* the reason is for reusing backend tx.
* so we don't call this.verifyOpened() here.
*/
GraphTransaction graphTx = this.graphTransaction.get();
if (graphTx == null) {
graphTx = openGraphTransaction();
this.graphTransaction.set(graphTx);
}
return graphTx;
}
實際通過 openGraphTransaction() 和 openSchemaTransaction(); 來創(chuàng)建事務(wù)對象。
hugegraph 的 addvertex 以及 對schema 的修改都是通過 這兩個對象的接口實現(xiàn)词渤。
對于 hugegraph 的事務(wù)管理牵舱,將在下一章重點接收。
到目前為止缺虐, hugegraph對象就創(chuàng)建好了芜壁,接口以使用相應(yīng)的方法。
請看下回分解志笼。