美文网首页
四 hugegraph源代码- 锁和事务

四 hugegraph源代码- 锁和事务

作者: NazgulSun | 来源:发表于2019-06-20 17:57 被阅读0次

    上一章说了事务的问题,下面就必然要看看如何实现锁机制的。

    ThreadLocal 实现事务管理

    还是从 addVertex 出发,调用api时,web server会
    根据从线程池分配一个线程给 用户,用户获取一个 hugegraph实例,
    并调用 addVertex方法。

        @Override
        public Vertex addVertex(Object... keyValues) {
            return this.graphTransaction().addVertex(keyValues);
        }
        
        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;
    }
        
    

    this.graphTransaction 是一个 private ThreadLocal<GraphTransaction> graphTransaction; 对象。
    ThreadLocal 经常被用于 多线程下的事务管理,本质上可以理解为一个 Map<Thread,Transaction>, 他的key
    为当前线程,也就是说为每个线程保留一个 Transaction对象。
    好了,到此位置,我们知道 不同用户的每一个 addVertex 操作都会有不同 的transaction 维护,
    那么很自然的就会提出一个问题,如果多个线程同时 添加一个节点, 会不会存在更新丢失的问题呢?

    比如,我对A节点,设置其值为 1, 另外一个用户后面对A节点设置为 3, 结果会不会是1 呢? hugeraph 是否做了保护。

    hugegraph 如何做 写的事务隔离

        public HugeVertex addVertex(HugeVertex vertex) {
            this.checkOwnerThread();
    
            // Override vertexes in local `removedVertexes`
            this.removedVertexes.remove(vertex.id());
            try {
                this.locksTable.lockReads(LockUtil.VERTEX_LABEL_DELETE,
                                          vertex.schemaLabel().id());
                this.locksTable.lockReads(LockUtil.INDEX_LABEL_DELETE,
                                          vertex.schemaLabel().indexLabels());
                // Ensure vertex label still exists from vertex-construct to lock
                this.graph().vertexLabel(vertex.schemaLabel().id());
                /*
                 * No need to lock VERTEX_LABEL_ADD_UPDATE, because vertex label
                 * update only can add nullable properties and user data, which is
                 * unconcerned with add vertex
                 */
                this.beforeWrite();
                this.addedVertexes.put(vertex.id(), vertex);
                this.afterWrite();
            } catch (Throwable e){
                this.locksTable.unlock();
                throw e;
            }
            return vertex;
        }
        
    

    从这里可以发现,addVetex 只做了 VERTEX_LABEL_DELETE ,INDEX_LABEL_DELETE 操作的互斥锁。
    也就是说在进行添加数据的时候, 不能对schema进行增删改查,但是不同的线程还是可以对同一个 vertex进行
    操作,那么就会存在丢失更新的问题。

    不知道是不是我代码看得不全? 还是hugegraph目前暂时不支持严格的事务隔离。

    hugegraph锁是如何实现和复用?

    我们看看LockUtils的代码

        public static final String INDEX_LABEL_DELETE = "il_delete";
        public static final String EDGE_LABEL_DELETE = "el_delete";
        public static final String VERTEX_LABEL_DELETE = "vl_delete";
        public static final String INDEX_LABEL_REBUILD = "il_rebuild";
        public static final String INDEX_LABEL_ADD_UPDATE = "il_add_update";
        public static final String EDGE_LABEL_ADD_UPDATE = "el_add_update";
        public static final String VERTEX_LABEL_ADD_UPDATE = "vl_add_update";
        public static final String PROPERTY_KEY_ADD_UPDATE = "pk_add_update";
    
        public static final long WRITE_WAIT_TIMEOUT = 30L;
    
        public static void init(String graph) {
            LockManager.instance().create(join(graph, INDEX_LABEL_DELETE));
            LockManager.instance().create(join(graph, EDGE_LABEL_DELETE));
            LockManager.instance().create(join(graph, VERTEX_LABEL_DELETE));
            LockManager.instance().create(join(graph, INDEX_LABEL_REBUILD));
            LockManager.instance().create(join(graph, INDEX_LABEL_ADD_UPDATE));
            LockManager.instance().create(join(graph, EDGE_LABEL_ADD_UPDATE));
            LockManager.instance().create(join(graph, VERTEX_LABEL_ADD_UPDATE));
            LockManager.instance().create(join(graph, PROPERTY_KEY_ADD_UPDATE));
        }
    

    考虑到整个操作过程中可能对不同的节点,关系,索引进行加锁处理,
    为了避免重复的锁对象的创建, hugegraph 使用了lockManager,实现把可能需创建的锁进行分类。比如
    针对 删除节点的 group,删除index 的LockGroup 等。

    当addVertex的时候,比如增加一个 Company 的节点。 lockManager会检查 Company 上是否已经有读锁,如果有就复用
    否则就创建。
    同样,在修改Company的schema的时候,则会获取一个Company 的写锁。
    就这样实现了全局的锁的复用。

    相关文章

      网友评论

          本文标题:四 hugegraph源代码- 锁和事务

          本文链接:https://www.haomeiwen.com/subject/zknjqctx.html