watcher implementing data structures and streaming diagrams
Note: The picture is too large, right-click new tab to open the picture, enlarge view
Client client receives notification message for watch event
All watcher final callbacks receive messages in the CLIENTCNXN internal class Sendthread. The XID field of the message body of the notification event notification that the server sends to the client is special, which is-1.
Class Sendthread extends Thread {private long lastpingsentns;
Private final Clientcnxnsocket Clientcnxnsocket;
Private random R = new Random (System.nanotime ());
Private Boolean isfirstconnect = true; void Readresponse (Bytebuffer incomingbuffer) throws IOException {Bytebufferinputstream bbis = new Bytebufferi
Nputstream (Incomingbuffer);
Binaryinputarchive Bbia = binaryinputarchive.getarchive (bbis);
Replyheader REPLYHDR = new Replyheader ();
Replyhdr.deserialize (Bbia, "header");
if (replyhdr.getxid () = =-2) {//-2 is the XID for pings if (log.isdebugenabled ()) {
Log.debug ("Got ping response for sessionid:0x" + long.tohexstring (SessionID)
+ "after" + ((System.nanotime ()-lastpingsentns)/1000000) + "MS");
} return;
} if (Replyhdr.getxid () = =-4) {//-4 is the XID for Authpacket
if (replyhdr.geterr () = = KeeperException.Code.AUTHFAILED.intValue ()) {state = states.auth_failed;
Eventthread.queueevent (New Watchedevent (Watcher.Event.EventType.None,
Watcher.Event.KeeperState.AuthFailed, null));
} if (log.isdebugenabled ()) {log.debug ("Got auth sessionid:0x"
+ long.tohexstring (sessionId));
} return; } if (Replyhdr.getxid () = =-1) {//Currently we are only interested in XID =-1 for WATCHEDEVENT events Notification//-1 mean s notification if (log.isdebugenabled ()) {Log.debug ("Got notification sessionid:0x "+ long.tohexstring (sessionId)); } watcherevent event = new Watcherevent ();
Watcherevent is used for serialization and deserialization, the internal field order and Watchedevent are fully consistent event.deserialize (Bbia, "response"); Convert from a server path to a client path if (Chrootpath! = null) {String server
Path = Event.getpath ();
if (Serverpath.compareto (Chrootpath) ==0) Event.setpath ("/"); else if (serverpath.length () > Chrootpath.length ()) Event.setpath (Serverpath.substring (chrootpa
Th.length ())); else {Log.warn ("Got Server path" + event.getpath () + "which is
Too short for chroot path "+ Chrootpath);
}} Watchedevent we = new Watchedevent (event); If(Log.isdebugenabled ()) {Log.debug ("Got" + We + "for SessionID 0x" + long.tohexstring (SessionID
)); } eventthread.queueevent (We);
The final event execution relies on the Eventthread thread, first in the Eventthread internal queue return; }//If SASL authentication is currently in progress, construct and//Send a response packet Imm
ediately, rather than queuing A//response as with other packets.
....
}
....
}
client-side access to watchedevent processing
The Eventthread Asynchronous thread run () function is as follows:
Class Eventthread extends Thread {private final linkedblockingqueue<object> waitingevents = new
Linkedblockingqueue<object> ();
@Override public void Run () {try {isrunning = true;
while (true) {Object event = Waitingevents.take ();
if (event = = Eventofdeath) {waskilled = true;
} else {processevent (event); } if (waskilled) synchronized (waitingevents) {if (Waitingeve
Nts.isempty ()) {isrunning = false;
Break }}}} catch (Interruptedexception e) {log.error ("Event Threa
D exiting due to interruption ", e);
} log.info ("Eventthread shut Down"); }
....
}
Server-Side
Server side, all the Znode node data additions and deletions, will trigger the event. Datatree Trigger Watcher entry
Now let's take the example of modifying Znode data
file: Datatree.java public Stat setData (String path, byte data[], int version, Long Zxid,
Long time) throws Keeperexception.nonodeexception {stat s = new Stat ();
DataNode n = nodes.get (path);
if (n = = null) {throw new keeperexception.nonodeexception ();
} byte lastdata[] = null;
Synchronized (n) {lastdata = N.data;
N.data = data;
N.stat.setmtime (time);
N.stat.setmzxid (ZXID);
N.stat.setversion (version);
N.copystat (s);
}//Now update if the path was in a quota subtree.
String Lastprefix; if (Lastprefix = Getmaxprefixwithquota (path)) = null) {this.updatebytes (lastprefix, (data = = null? 0:data.l
Ength)-(Lastdata = = null? 0:lastdata.length));
} datawatches.triggerwatch (path, eventtype.nodedatachanged);
return s; }
At last, call Datawatchers.triggerwatch (path, eventtype.nodedatachanged) to watcher callback to the node of the path path.
Files: Watchmanager.java public set<watcher> triggerwatch (String path, EventType type, set<watcher> supress) {
Watchedevent e = new Watchedevent (type, keeperstate.syncconnected, path);
Hashset<watcher> watchers;
Synchronized (this) {watchers = Watchtable.remove (path); if (watchers = = NULL | | watchers.isempty ()) {if (log.istraceenabled ()) {ZooTrace.log Tracemessage (LOG, Zootrace.event_delivery_trace_mask, "No watchers
For "+ path");
} return null;
} for (Watcher w:watchers) {hashset<string> paths = Watch2paths.get (w);
if (paths! = null) {paths.remove (path); }}} for (Watcher w:watchers) {//Here's watcher W actually the server Proxy client watch object, for NIOSERVERCNX
Class N if (supress! = null && supress.contains (W)) {continue;
} w.process (e);
} return watchers; }
NIOSERVERCNXN Proxy watcher for data communication
First, the next nioservercnxn, which is the client and server to communicate the package class, contains the socket connection input, OutputStream, is derived from the NIO selectedkey input output.
Another important function of NIOSERVERCNXN, which enabled him to implement the Watcher interface, was to complete the agent for the client watcher.
File: Nioservercnxn
@Override
synchronized public void process (Watchedevent event) {
Replyheader h = new Replyheader ( -1, -1l, 0); Note here that XID is 1
if (log.istraceenabled ()) {
zootrace.logtracemessage (LOG, Zootrace.event_delivery_trace_mask ,
"Deliver event" + Event + "to 0x"
+ long.tohexstring (this.sessionid) +
"through" + This);
}
Convert watchedevent to a type so can be sent over the wire
watcherevent e = Event.getwrapper ();
Sendresponse (H, E, "notification"); Serialization of Watcherevent, network transport
}