Browse Source

[1261] overall comment update

JINMEI Tatuya 13 years ago
parent
commit
fcd39b6e84
2 changed files with 60 additions and 9 deletions
  1. 1 0
      src/bin/xfrin/tests/xfrin_test.py
  2. 59 9
      src/bin/xfrin/xfrin.py.in

+ 1 - 0
src/bin/xfrin/tests/xfrin_test.py

@@ -422,6 +422,7 @@ class TestXfrinIXFRAdd(TestXfrinState):
         self.assertEqual([], self.conn._diff.get_buffer())
         self.assertEqual([], self.conn._diff.get_buffer())
 
 
     def test_handle_new_delete(self):
     def test_handle_new_delete(self):
+        self.conn._end_serial = 1234
         # SOA RR whose serial is the current one means we are going to a new
         # SOA RR whose serial is the current one means we are going to a new
         # difference, starting with removing that SOA.
         # difference, starting with removing that SOA.
         self.conn._diff.add_data(self.ns_rrset) # put some dummy change
         self.conn._diff.add_data(self.ns_rrset) # put some dummy change

+ 59 - 9
src/bin/xfrin/xfrin.py.in

@@ -144,26 +144,70 @@ class XfrinState:
     response RRs have already been received.
     response RRs have already been received.
     NOTE: the AXFR part of the state machine is incomplete at this point.
     NOTE: the AXFR part of the state machine is incomplete at this point.
 
 
-    This implementation uses the state design patter, where each state
-    is represented as a subclass of the base XfrinState class.  The base
-    class defines two abstract interfaces: handle_rr() and finish_message().
-    These methods handle specific part of XFR protocols and (if necessary)
-    perform the state transition.
+    The following diagram summarizes the state transition.  After sending
+    the query, xfrin starts the process with the InitialSOA state (all
+    IXFR/AXFR response begins with an SOA).  When it reaches IXFREnd
+    (or AXFREnd, which is not yet implemented and not shown here), the
+    process successfully completes.
+
+
+            (recv SOA)       (AXFR-style IXFR)
+    InitialSOA------->FirstData------------->AXFR
+                          |                     (non SOA, delete)
+               (pure IXFR,|                           +-------+
+            keep handling)|             (Delete SOA)  V       |
+                          + ->IXFRDeleteSOA------>IXFRDelete--+
+                                   ^                   |
+                (see SOA, not end, |          (see SOA)|
+            commit, keep handling) |                   |
+                                   |                   V
+                      +---------IXFRAdd<----------+IXFRAddSOA
+        (non SOA, add)|         ^  |    (Add SOA)
+                      ----------+  |
+                                   |(see SOA w/ end serial, commit changes)
+                                   V
+                                IXFREnd
+
+    This implementation uses the state design pattern, where each state
+    is represented as a subclass of the base XfrinState class.  Each concrete
+    subclass of XfrinState is assumed to define two methods: handle_rr() and
+    finish_message().  These methods handle specific part of XFR protocols
+    and (if necessary) perform the state transition.
+
+    Conceptually, XfrinState and its subclasses are a "friend" of
+    XfrinConnection and are assumed to be allowed to access its internal
+    information (even though Python does not have a strict access control
+    between different classes).
 
 
     The XfrinState and its subclasses are designed to be stateless, and
     The XfrinState and its subclasses are designed to be stateless, and
     can be used as singleton objects.  For now, however, we always instantiate
     can be used as singleton objects.  For now, however, we always instantiate
     a new object for every state transition, partly because the introduction
     a new object for every state transition, partly because the introduction
     of singleton will make a code bit complicated, and partly because
     of singleton will make a code bit complicated, and partly because
     the overhead of object instantiotion wouldn't be significant for xfrin.
     the overhead of object instantiotion wouldn't be significant for xfrin.
+
     '''
     '''
     def set_xfrstate(self, conn, new_state):
     def set_xfrstate(self, conn, new_state):
         '''Set the XfrConnection to a given new state.
         '''Set the XfrConnection to a given new state.
 
 
         As a "friend" class, this method intentionally gets access to the
         As a "friend" class, this method intentionally gets access to the
         connection's "private" method.
         connection's "private" method.
+
         '''
         '''
         conn._XfrinConnection__set_xfrstate(new_state)
         conn._XfrinConnection__set_xfrstate(new_state)
 
 
+    def handle_rr(self, conn):
+        '''Handle one RR of an XFR response message.
+
+        Depending on the state, the RR is generally added or deleted in the
+        corresponding data source, or in some special cases indicates
+        a specifi transition, such as starting a new IXFR difference
+        sequence or completing the session.
+
+        All subclass has their specific behaviors for this method, so
+        there is no default definition.
+        '''
+        pass
+
     def finish_message(self, conn):
     def finish_message(self, conn):
         '''Perform any final processing after handling all RRs of a response.
         '''Perform any final processing after handling all RRs of a response.
 
 
@@ -183,9 +227,10 @@ class XfrinInitialSOA(XfrinState):
         conn._end_serial = get_soa_serial(rr.get_rdata()[0])
         conn._end_serial = get_soa_serial(rr.get_rdata()[0])
 
 
         # FIXME: we need to check the serial is actually greater than ours.
         # FIXME: we need to check the serial is actually greater than ours.
-        # To do so, however, we need a way to find records from datasource.
-        # Complete that part later as a separate task.  (Always performing
-        # xfr could be inefficient, but shouldn't do any harm otherwise)
+        # To do so, however, we need to implement serial number arithmetic.
+        # Although it wouldn't be a big task, we'll leave it for a separate
+        # task for now.  (Always performing xfr could be inefficient, but
+        # shouldn't do any harm otherwise)
 
 
         self.set_xfrstate(conn, XfrinFirstData())
         self.set_xfrstate(conn, XfrinFirstData())
         return True
         return True
@@ -298,11 +343,16 @@ class XfrinConnection(asyncore.dispatcher):
         '''
         '''
 
 
         asyncore.dispatcher.__init__(self, map=sock_map)
         asyncore.dispatcher.__init__(self, map=sock_map)
+
+        # The XFR state.  Coceptually this is purely private, so we emphasize
+        # the fact by the double underscore.  Other classes are assumed to
+        # get access to this via get_xfrstate(), and only XfrinState classes
+        # are assumed to be allowed to modify it via __set_xfrstate().
         self.__state = None
         self.__state = None
+
         # Requested transfer type (RRType.AXFR or RRType.IXFR).  The actual
         # Requested transfer type (RRType.AXFR or RRType.IXFR).  The actual
         # transfer type may differ due to IXFR->AXFR fallback:
         # transfer type may differ due to IXFR->AXFR fallback:
         self._request_type = None
         self._request_type = None
-        self._end_serial = None # essentially private
 
 
         # Zone parameters
         # Zone parameters
         self._zone_name = zone_name
         self._zone_name = zone_name