zookeeper源码分析----节点创建流程

来源:互联网 发布:腾讯微信数据库多大 编辑:程序博客网 时间:2024/06/05 01:54

        

        zookeeper作为一个c/s模式的应用程序,在客户端主要是处理(封装)用户请求,序列化,然后以socket方式发送到服务端,服务端进行反序列化之后处理客户端请求数据。

        下面是客户端主要的代码:

        ZooKeeperMain:主要是处理zookeeper命令行模式的一些操作,其中,处理创建的部分代码如下:

if (cmd.equals("create") && args.length >= 3) {            int first = 0;            CreateMode flags = CreateMode.PERSISTENT;            if ((args[1].equals("-e") && args[2].equals("-s"))                    || (args[1]).equals("-s") && (args[2].equals("-e"))) {                first+=2;                flags = CreateMode.EPHEMERAL_SEQUENTIAL;            } else if (args[1].equals("-e")) {                first++;                flags = CreateMode.EPHEMERAL;            } else if (args[1].equals("-s")) {                first++;                flags = CreateMode.PERSISTENT_SEQUENTIAL;            }            if (args.length == first + 4) {                acl = parseACLs(args[first+3]);            }            path = args[first + 1];            String newPath = zk.create(path, args[first+2].getBytes(), acl,                    flags);            System.err.println("Created " + newPath);        }
        从代码中可以看出,zookeeper在处理命令行命令的时候create等命令只支持小写。在处理create命令之后,会调用ZooKeeper(java编程时所使用客户端)对象来创建节点,ZooKeeper将创建节点的命令封装成一个CreateRequest(实现Record接口)对象,然后将对象序列化发送至服务端(通过NIO客户端ClientCnxnSocketNIO)。

        服务端代码:

        ZooKeeperServer:主要处理客户端请求,其中,方法processPacket是将请求数据(ByteBuffer)封装成Request对象,代码如下:

Request si = new Request(cnxn, cnxn.getSessionId(), h.getXid(),                  h.getType(), incomingBuffer, cnxn.getAuthInfo());                si.setOwner(ServerCnxn.me);                submitRequest(si);

        该对象提交至PrepRequestProcessor对象中,该对象会提交至队列submittedRequests:

public void processRequest(Request request) {        // request.addRQRec(">prep="+zks.outstandingChanges.size());        submittedRequests.add(request);    }
        该对象被实例化为一个独立线程在运行,下面是其中run方法:

public void run() {        try {            while (true) {                Request request = submittedRequests.take();                long traceMask = ZooTrace.CLIENT_REQUEST_TRACE_MASK;                if (request.type == OpCode.ping) {                    traceMask = ZooTrace.CLIENT_PING_TRACE_MASK;                }                if (LOG.isTraceEnabled()) {                    ZooTrace.logRequest(LOG, traceMask, 'P', request, "");                }                if (Request.requestOfDeath == request) {                    break;                }                pRequest(request);            }        } catch (InterruptedException e) {            LOG.error("Unexpected interruption", e);        } catch (RequestProcessorException e) {            if (e.getCause() instanceof XidRolloverException) {                LOG.info(e.getCause().getMessage());            }            LOG.error("Unexpected exception", e);        } catch (Exception e) {            LOG.error("Unexpected exception", e);        }        LOG.info("PrepRequestProcessor exited loop!");    }
pRequest直接调用方法<span style="font-family: Arial, Helvetica, sans-serif;">pRequest2Txn,</span><span style="font-family: Arial, Helvetica, sans-serif;">pRequest2Txn部分代码如下</span><span style="font-family: Arial, Helvetica, sans-serif;">:</span>
case OpCode.create:                                zks.sessionTracker.checkSession(request.sessionId, request.getOwner());                CreateRequest createRequest = (CreateRequest)record;                   if(deserialize)                    ByteBufferInputStream.byteBuffer2Record(request.request, createRequest);                String path = createRequest.getPath();                int lastSlash = path.lastIndexOf('/');                if (lastSlash == -1 || path.indexOf('\0') != -1 || failCreate) {                    LOG.info("Invalid path " + path + " with session 0x" +                            Long.toHexString(request.sessionId));                    throw new KeeperException.BadArgumentsException(path);                }                List<ACL> listACL = removeDuplicates(createRequest.getAcl());                if (!fixupACL(request.authInfo, listACL)) {                    throw new KeeperException.InvalidACLException(path);                }                String parentPath = path.substring(0, lastSlash);                ChangeRecord parentRecord = getRecordForPath(parentPath);                checkACL(zks, parentRecord.acl, ZooDefs.Perms.CREATE,                        request.authInfo);                int parentCVersion = parentRecord.stat.getCversion();                CreateMode createMode =                    CreateMode.fromFlag(createRequest.getFlags());                if (createMode.isSequential()) {                    path = path + String.format(Locale.ENGLISH, "%010d", parentCVersion);                }                try {                    PathUtils.validatePath(path);                } catch(IllegalArgumentException ie) {                    LOG.info("Invalid path " + path + " with session 0x" +                            Long.toHexString(request.sessionId));                    throw new KeeperException.BadArgumentsException(path);                }                try {                    if (getRecordForPath(path) != null) {                        throw new KeeperException.NodeExistsException(path);                    }                } catch (KeeperException.NoNodeException e) {                    // ignore this one                }                boolean ephemeralParent = parentRecord.stat.getEphemeralOwner() != 0;                if (ephemeralParent) {                    throw new KeeperException.NoChildrenForEphemeralsException(path);                }                int newCversion = parentRecord.stat.getCversion()+1;                request.txn = new CreateTxn(path, createRequest.getData(),                        listACL,                        createMode.isEphemeral(), newCversion);                StatPersisted s = new StatPersisted();                if (createMode.isEphemeral()) {                    s.setEphemeralOwner(request.sessionId);                }                parentRecord = parentRecord.duplicate(request.hdr.getZxid());                parentRecord.childCount++;                parentRecord.stat.setCversion(newCversion);                addChangeRecord(parentRecord);                addChangeRecord(new ChangeRecord(request.hdr.getZxid(), path, s,                        0, listACL));                break;

        从以上方法中,可以看出zookeeper对于SEQUENTIAL、EPHEMERAL类型节点的处理,特别是SEQUENTIAL类型的节点,对于path的处理比较明显。

        另外,对于EPHEMERAL类型的节点,可以从DataTree.createNode()方法以及PrepRequestProcessor.pRequest2Txn()方法中closeSession看到,当session关闭时,将节点类型为EPHEMERAL的数据移除。


0 0
原创粉丝点击