Zookeeper (seven) distributed lock

Source: http://blog.csdn.net/java2000_wl/article/details/8694270
Comments:
Implementation ideas for acquiring locks:

1. First create a lock directory (znode), which is usually used to describe the locked entity, called: /lock_node

2. The client who wants to obtain the lock creates a znode in the lock directory as a child node of the lock /lock_node, and the node type is an ordered temporary node (EPHEMERAL_SEQUENTIAL);

        for example: two clients create znodes, respectively /lock_node lock_node/lock-1 and /lock_node/lock-2

3. The current client calls getChildren (/lock_node) to get all child nodes of the lock directory, without setting watch, and then obtains sibling nodes smaller than itself (created in step 2)

4. Step 3 Get the node smaller than yourself does not exist && The smallest node is the same as the one created in step 2, indicating that the current client sequence number is the smallest, the lock is obtained, and the end.

5. The client monitors (watches) the state of the second-smallest ordered temporary node relative to its own

6. If the state of the monitored second-smallest node changes, it jumps to step 3 and continues the subsequent operations until it exits the lock competition.

[java] view plain copy
print?

    public synchronized boolean lock() throws KeeperException, InterruptedException { 
           if (isClosed()) { 
               return false; 
           } 
           // If the lock directory does not exist, create a lock directory, the node type is permanent type 
           ensurePathExists(dir); 
     
           // Create a lock node, node type EPHEMERAL_SEQUENTIAL  
           // If there is no node smaller than itself and the smallest node is the same as the currently created one The same node obtains the lock  // If the lock is not obtained successfully, set watch            return (Boolean) retryOperation(zop) 
           for the current minor node  ;        }  Create a lock directory [java] view plain copy print?     protected void ensurePathExists(String path) {          ensureExists(path, null, acl, CreateMode.PERSISTENT);      }  [java] view plain copy print?     protected void ensureExists(final String path, final byte[] data, 















            final List<ACL> acl, final CreateMode flags) { 
        try { 
            retryOperation(new ZooKeeperOperation() { 
                public boolean execute() throws KeeperException, InterruptedException { 
                    // Create lock directory 
                    Stat stat = zookeeper.exists(path, false); 
                    // If the node exists, return directly 
                    if (stat != null) { 
                        return true; 
                    } 
                    // Create node 
                    // data is null 
                    // flags is persistent node 
                    zookeeper.create(path, data, acl, flags); 
                    return true; 
                } 
            }); 
        } catch (KeeperException e) { 
            LOG.warn("Caught: " + e, e); 
        } catch (InterruptedException e) { 
            LOG.warn("Caught: " + e, e); 
        } 
    } 


create lock node, get all the nodes in the lock directory, if the lock is successfully obtained for the smallest node

[java] view plain copy
print?

        /**
         * the command that is run and retried for actually 
         * obtaining the lock
         * @return if the command was successful or not
         */ 
        public boolean execute() throws KeeperException, InterruptedException { 
            do { 
                if (id == null) { 
                    long sessionId = zookeeper.getSessionId(); 
                    String prefix = "x-" + sessionId + "-"; 
                    // lets try look up the current ID if we failed  
                    // in the middle of creating the znode 
                    findPrefixInChildren(prefix, zookeeper, dir); 
                    idName = new ZNodeName(id); 
                } 
                if (id != null) { 
                    List<String> names = zookeeper.getChildren(dir, false); 
                    if (names.isEmpty()) { 
                        LOG.warn("No children in: " + dir + " when we've just " + 
                        "created one! Lets recreate it..."); 
                        // lets force the recreation of the id 
                        id = null; 
                    } else { 
                        // lets sort them explicitly (though they do seem to come back in order ususally  
                        SortedSet<ZNodeName> sortedNames = new TreeSet<ZNodeName>(); 
                        for (String name : names) { 
                            sortedNames.add(new ZNodeName(dir + "/" + name)); 
                        } 
                        // 获得最小节点 
                        ownerId = sortedNames.first().getName(); 
                        // lock_1, lock_2, lock_3  传入参数lock_2  返回lock_1 
                        SortedSet<ZNodeName> lessThanMe = sortedNames.headSet(idName); 
                        if (!lessThanMe.isEmpty()) { 
                            ZNodeName lastChildName = lessThanMe.last(); 
                            lastChildId = lastChildName.getName(); 
                            if (LOG.isDebugEnabled()) { 
                                LOG.debug("watching less than me node: " + lastChildId); 
                            } 
                            // 次小节点设置watch  
                            Stat stat = zookeeper.exists(lastChildId, new LockWatcher()); 
                            if (stat != null) { 
                                return Boolean.FALSE; 
                            } else { 
                                LOG.warn("Could not find the" + 
                                        " stats for less than me: " + lastChildName.getName()); 
                            } 
                        } else { 
                            // The smallest node in the lock directory is the same as the current client creation 
                            if ( isOwner()) { 
                                if (callback != null) { 
                                    callback.lockAcquired(); 
                                } 
                                // acquire lock 
                                return Boolean.TRUE; 
                            } 
                        } 
                    } 
                } 
            } 
            while (id == null); 
            return Boolean.FALSE; 
        } 
    }; 


[java] view plain copy
print?

    private void findPrefixInChildren(String prefix, ZooKeeper zookeeper, String dir)  
                throws KeeperException, InterruptedException { 
                // 获取锁目录下的所有子节点 
                List<String> names = zookeeper.getChildren(dir, false); 
                for (String name : names) { 
                    //x-sessionId- 
                    if (name.startsWith(prefix)) { 
                        id = name; 
                        if (LOG.isDebugEnabled()) { 
                            LOG.debug("Found id created last time: " + id); 
                        } 
                        break; 
                    } 
                } 
                // There is no child node creation child corresponding to the current session in the current lock directory Node node type is temporary sequence node 
                if (id == null) { 
                    // dir/x-sessionId-i 
                    id = zookeeper.create(dir + "/" + prefix, data,  
                            getAcl(), EPHEMERAL_SEQUENTIAL); 
     
                    if (LOG .isDebugEnabled()) { 
                        LOG.debug("Created id: " + id); 
                    } 
                } 


Release the lock:

Release the lock is very simple, delete the ordered temporary node created in step 1. In addition, if the client process dies or the connection fails, the corresponding node will also be deleted.

[java] view plain copy
print?

    public synchronized void unlock() throws RuntimeException { 
            
           if (!isClosed() && id != null) { 
               // we don't need to retry this operation in the case of failure 
               // as ZK will remove ephemeral files and we don't wanna hang 
               // this process when closing if we cannot reconnect to ZK 
               try { 
                    
                   ZooKeeperOperation zopdel = new ZooKeeperOperation() { 
                       public boolean execute() throws KeeperException, 
                           InterruptedException { 
                        // 删除节点  忽略版本 
                           zookeeper.delete(id, -1);    
                           return Boolean.TRUE; 
                       } 
                   }; 
                   zopdel.execute(); 
               } catch (InterruptedException e) { 
                   LOG.warn("Caught: " + e, e); 
                   //set that we have been interrupted. 
                  Thread.currentThread().interrupt(); 
               } catch (KeeperException.NoNodeException e) { 
                   // do nothing 
               } catch (KeeperException e) { 
                   LOG.warn("Caught: " + e, e); 
                   throw (RuntimeException) new RuntimeException(e.getMessage()). 
                       initCause(e); 
               } 
               finally { 
                   if (callback != null) { 
                       callback.lockReleased(); 
                   } 
                   id = null; 
               } 
           } 
       } 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326484882&siteId=291194637