Parcourir la source

Merge branch 'trac3006'

Mukund Sivaraman il y a 11 ans
Parent
commit
c400406661

+ 10 - 0
configure.ac

@@ -1132,6 +1132,14 @@ AC_ARG_ENABLE(logger-checks, [AC_HELP_STRING([--enable-logger-checks],
 AM_CONDITIONAL(ENABLE_LOGGER_CHECKS, test x$enable_logger_checks != xno)
 AM_COND_IF([ENABLE_LOGGER_CHECKS], [AC_DEFINE([ENABLE_LOGGER_CHECKS], [1], [Check logger messages?])])
 
+# Check for asciidoc
+AC_PATH_PROG(ASCIIDOC, asciidoc, no)
+AM_CONDITIONAL(HAVE_ASCIIDOC, test "x$ASCIIDOC" != "xno")
+
+# Check for plantuml
+AC_PATH_PROG(PLANTUML, plantuml, no)
+AM_CONDITIONAL(HAVE_PLANTUML, test "x$PLANTUML" != "xno")
+
 # Check for valgrind
 AC_PATH_PROG(VALGRIND, valgrind, no)
 AM_CONDITIONAL(HAVE_VALGRIND, test "x$VALGRIND" != "xno")
@@ -1171,6 +1179,8 @@ AM_COND_IF([HAVE_OPTRESET], [AC_DEFINE([HAVE_OPTRESET], [1], [Check for optreset
 AC_CONFIG_FILES([Makefile
                  doc/Makefile
                  doc/guide/Makefile
+                 doc/design/Makefile
+                 doc/design/datasrc/Makefile
                  compatcheck/Makefile
                  src/Makefile
                  src/bin/Makefile

+ 1 - 1
doc/Makefile.am

@@ -1,4 +1,4 @@
-SUBDIRS = guide
+SUBDIRS = guide design
 
 EXTRA_DIST = version.ent.in differences.txt Doxyfile Doxyfile-xml
 

+ 1 - 0
doc/design/Makefile.am

@@ -0,0 +1 @@
+SUBDIRS = datasrc

+ 3 - 0
doc/design/datasrc/.gitignore

@@ -0,0 +1,3 @@
+/*.html
+/*.png
+/*.xml

+ 30 - 0
doc/design/datasrc/Makefile.am

@@ -0,0 +1,30 @@
+UML_FILES = \
+	overview.txt \
+	auth-local.txt \
+	auth-mapped.txt \
+	memmgr-mapped-init.txt \
+	memmgr-mapped-reload.txt
+
+TEXT_FILES = \
+	data-source-classes.txt
+
+devel: $(patsubst %.txt, %.png, $(UML_FILES)) $(patsubst %.txt, %.html, $(TEXT_FILES))
+
+.txt.html:
+if HAVE_ASCIIDOC
+	$(AM_V_GEN) $(ASCIIDOC) -n $<
+else
+	@echo "*** asciidoc is required to regenerate $(@) ***"; exit 1;
+endif
+
+.txt.png:
+if HAVE_PLANTUML
+	$(AM_V_GEN) $(PLANTUML) $<
+else
+	@echo "*** plantuml is required to regenerate $(@) ***"; exit 1;
+endif
+
+CLEANFILES = \
+	$(patsubst %.txt, %.png, $(UML_FILES)) \
+	$(patsubst %.txt, %.html, $(TEXT_FILES)) \
+	$(patsubst %.txt, %.xml, $(TEXT_FILES))

+ 137 - 0
doc/design/datasrc/auth-local.txt

@@ -0,0 +1,137 @@
+@startuml
+
+participant auth as "b10-auth"
+[-> auth: new/initial config\n(datasrc cfg)
+activate auth
+
+participant list as "Configurable\nClientList"
+create list
+auth -> list: <<construct>>
+
+auth -> list: configure(cfg)
+activate list
+
+create CacheConfig
+list -> CacheConfig: <<construct>> (cfg)
+
+participant zt_segment as "ZoneTable\nSegment\n(Local)"
+create zt_segment
+list -> zt_segment: <<construct>>
+activate zt_segment
+
+create ZoneTable
+zt_segment -> ZoneTable: <<construct>>
+
+deactivate zt_segment
+
+list -> zt_segment: isWritable()
+activate zt_segment
+note over zt_segment: Local segments are\nalways writable
+zt_segment --> list: true
+deactivate zt_segment
+
+loop for each zone in CacheConfig
+list -> CacheConfig: getLoadAction()
+activate CacheConfig
+
+create LoadAction
+CacheConfig -> LoadAction: <<construct>>
+
+participant LoadAction.2
+
+CacheConfig --> list : LoadAction
+
+deactivate CacheConfig
+
+create ZoneWriter
+list -> ZoneWriter: <<construct>> (load_action)
+
+participant ZoneWriter.2
+
+list -> ZoneWriter: load()
+activate ZoneWriter
+ZoneWriter -> LoadAction: (funcall)
+activate LoadAction
+
+create ZoneData
+LoadAction -> ZoneData: <<construct>> via helpers
+
+participant ZoneData.2
+
+LoadAction --> ZoneWriter: ZoneData
+deactivate LoadAction
+deactivate ZoneWriter
+
+list -> ZoneWriter: install()
+activate ZoneWriter
+
+ZoneWriter -> ZoneTable: addZone(ZoneData)
+activate ZoneTable
+ZoneTable --> ZoneWriter: NULL (no old data)
+deactivate ZoneTable
+
+deactivate ZoneWriter
+
+end
+
+deactivate list
+deactivate auth
+
+...
+
+[-> auth: reload\n(zonename)
+activate auth
+
+auth -> list: getCachedZoneWriter\n(zone_name)
+activate list
+
+list -> CacheConfig: getLoadAction()
+activate CacheConfig
+
+create LoadAction.2
+CacheConfig -> LoadAction.2: <<construct>>
+
+CacheConfig --> list : LoadAction.2
+
+deactivate CacheConfig
+
+create ZoneWriter.2
+list -> ZoneWriter.2: <<construct>> (load_action)
+
+list --> auth: ZoneWriter.2
+
+deactivate list
+
+
+auth -> ZoneWriter.2: load()
+activate ZoneWriter.2
+ZoneWriter.2 -> LoadAction.2: (funcall)
+activate LoadAction.2
+
+create ZoneData.2
+LoadAction.2 -> ZoneData.2: <<construct>> via helpers
+
+LoadAction.2 --> ZoneWriter.2: ZoneData.2
+deactivate LoadAction.2
+deactivate ZoneWriter.2
+
+auth -> ZoneWriter.2: install()
+activate ZoneWriter.2
+
+ZoneWriter.2 -> ZoneTable: addZone(ZoneData.2)
+activate ZoneTable
+ZoneTable --> ZoneWriter.2: ZoneData (old data)
+deactivate ZoneTable
+
+deactivate ZoneWriter.2
+
+auth -> ZoneWriter.2: cleanup()
+activate ZoneWriter.2
+
+ZoneWriter.2 -> ZoneData: <<destroy>>
+destroy ZoneData
+deactivate ZoneWriter.2
+
+deactivate auth
+
+@enduml

+ 98 - 0
doc/design/datasrc/auth-mapped.txt

@@ -0,0 +1,98 @@
+@startuml
+
+participant auth as "b10-auth"
+[-> auth: new/initial config\n(datasrc cfg)
+activate auth
+
+participant list as "Configurable\nClientList"
+create list
+auth -> list: <<construct>>
+
+auth -> list: configure(cfg)
+activate list
+
+create CacheConfig
+list -> CacheConfig: <<construct>> (cfg)
+
+participant zt_segment as "ZoneTable\nSegment\n(Mapped)"
+create zt_segment
+list -> zt_segment: <<construct>>
+
+list -> zt_segment: isWritable()
+activate zt_segment
+note over zt_segment: Segment not writable\nwhen not reset
+zt_segment --> list: false
+deactivate zt_segment
+
+deactivate list
+
+auth -> list: getStatus()
+activate list
+list --> auth: DataSourceStatus[]
+deactivate list
+
+[<- auth: subscribe to\nmemmgr group
+
+deactivate auth
+
+...
+
+[-> auth: command from\nmemmgr\n(datasrc_name,\nsegmentparam)
+activate auth
+
+auth -> list: resetMemorySegment\n(datasrc_name,\nREAD_ONLY,\nsegmentparam)
+activate list
+
+list -> zt_segment: reset\n(READ_ONLY,\nsegmentparam)
+activate zt_segment
+
+participant segment as "Memory\nSegment\n(Mapped)"
+create segment
+zt_segment -> segment: <<construct>>
+
+deactivate zt_segment
+deactivate list
+deactivate auth
+
+...
+
+[-> auth: command from\nmemmgr\n(datasrc_name,\nsegmentparam)
+activate auth
+
+auth -> list: resetMemorySegment\n(datasrc_name,\nREAD_ONLY,\nsegmentparam)
+activate list
+
+list -> zt_segment: reset\n(READ_ONLY,\nsegmentparam)
+activate zt_segment
+
+zt_segment -> segment: <<destroy>>
+destroy segment
+
+participant segment.2 as "Memory\nSegment\n(Mapped)\n2"
+create segment.2
+zt_segment -> segment.2: <<construct>>
+
+deactivate zt_segment
+deactivate list
+deactivate auth
+
+...
+
+[-> auth: reload\n(zonename)
+activate auth
+
+auth -> list: getCachedZoneWriter\n(zone_name)
+activate list
+
+list -> zt_segment: isWritable()
+activate zt_segment
+note over zt_segment: Segment not writable\nas it is READ_ONLY
+zt_segment --> list: false
+deactivate zt_segment
+
+list --> auth: CACHE_NOT_WRITABLE
+deactivate list
+
+deactivate auth
+
+@enduml

+ 364 - 0
doc/design/datasrc/data-source-classes.txt

@@ -0,0 +1,364 @@
+Data Source Library Classes
+===========================
+
+About this document
+-------------------
+
+This memo describes major classes used in the data source library,
+mainly focusing on handling in-memory cache with consideration of the
+shared memory support.  It will give an overview of the entire design
+architecture and some specific details of how these classes are expected
+to be used.
+
+Before reading, the higher level inter-module protocol should be understood:
+http://bind10.isc.org/wiki/SharedMemoryIPC
+
+Overall relationships between classes
+-------------------------------------
+
+The following diagram shows major classes in the data source library
+related to in-memory caches and their relationship.
+
+image::overview.png[Class diagram showing overview of relationships]
+
+Major design decisions of this architecture are:
+
+* Keep each class as concise as possible, each focusing on one or
+  small set of responsibilities.  Smaller classes are generally easier
+  to understand (at the cost of understanding how they work in the
+  "big picture" of course) and easier to test.
+
+* On a related point, minimize dependency to any single class.  A
+  monolithic class on which many others are dependent is generally
+  difficult to maintain because you'll need to ensure a change to the
+  monolithic class doesn't break anything on any other classes.
+
+* Use polymorphism for any "fluid" behavior, and hide specific details
+  under abstract interfaces so implementation details won't be
+  directly referenced from any other part of the library.
+  Specifically, the underlying memory segment type (local, mapped, and
+  possibly others) and the source of in-memory data (master file or
+  other data source) are hidden via a kind of polymorphism.
+
+* Separate classes directly used by applications from classes that
+  implement details.  Make the former classes as generic as possible,
+  agnostic about implementation specific details such as the memory
+  segment type (or, ideally and where possible, whether it's for
+  in-memory cache or the underlying data source).
+
+The following give a summarized description of these classes.
+
+* `ConfigurableClientList`: The front end to application classes.  An
+  application that uses the data source library generally maintains
+  one or more `ConfigurableClientList` object (usually one per RR
+  class, or when we support views, probably one per view).  This class
+  is a container of sets of data source related classes, providing
+  accessor to these classes and also acting as a factory of other
+  related class objects.  Note: Due to internal implementation
+  reasons, there is a base class for `ConfigurableClientList` named
+  `ClientList` in the C++ version, and applications are expected to
+  use the latter.  But conceptually `ConfigurableClientList` is an
+  independent value class; the inheritance is not for polymorphism.
+  Note also that the Python version doesn't have the base class.
+
+* `DataSourceInfo`: this is a straightforward tuple of set of class
+  objects corresponding to a single data source, including
+  `DataSourceClient`, `CacheConfig`, and `ZoneTableSegment`.
+  `ConfigurableClientList` maintains a list of `DataSourceInfo`, one
+  for each data source specified in its configuration.
+
+* `DataSourceClient`: The front end class to applications for a single
+  data source.  Applications will get a specific `DataSourceClient`
+  object by `ConfigurableClientList::find()`.
+  `DataSourceClient` itself is a set of factories for various
+  operations on the data source such as lookup or update.
+
+* `CacheConfig`: library internal representation of in-memory cache
+  configuration for a data source.  It knows which zones are to be
+  cached and where the zone data (RRs) should come from, either from a
+  master file or other data source.  With this knowledge it will
+  create an appropriate `LoadAction` object.  Note that `CacheConfig`
+  isn't aware of the underlying memory segment type for the in-memory
+  data.  It's intentionally separated from this class (see the
+  conciseness and minimal-dependency design decisions above).
+
+* `ZoneTableSegment`: when in-memory cache is enabled, it provides
+  memory-segment-type independent interface to the in-memory data.
+  This is an abstract base class (see polymorphism in the design
+  decisions) and inherited by segment-type specific subclasses:
+  `ZoneTableSegmentLocal` and `ZoneTableSegmentMapped` (and possibly
+  others).  Any subclass of `ZoneTableSegment` is expected to maintain
+  the specific type of `MemorySegment` object.
+
+* `ZoneWriter`: a frontend utility class for applications to update
+  in-memory zone data (currently it can only load a whole zone and
+  replace any existing zone content with a new one, but this should be
+  extended so it can handle partial updates).
+  Applications will get a specific `ZoneWriter`
+  object by `ConfigurableClientList::getCachedZoneWriter()`.
+  `ZoneWriter` is constructed with `ZoneableSegment` and `LoadAction`.
+  Since these are abstract classes, `ZoneWriter` doesn't have to be
+  aware of "fluid" details.  It's only responsible for "somehow" preparing
+  `ZoneData` for a new version of a specified zone using `LoadAction`,
+  and installing it in the `ZoneTable` (which can be accessed via
+  `ZoneTableSegment`).
+
+* `DataSourceStatus`: created by `ConfigurableClientList::getStatus()`,
+  a straightforward tuple that represents some status information of a
+  specific data source managed in the `ConfigurableClientList`.
+  `getStatus()` generates `DataSourceStatus` for all data sources
+  managed in it, and returns them as a vector.
+
+* `ZoneTableAccessor`, `ZoneTableIterator`: frontend classes to get
+  access to the conceptual "zone table" (a set of zones) stored in a
+  specific data source.  In particular, `ZoneTableIterator` allows
+  applications to iterate over all zones (by name) stored in the
+  specific data source.
+  Applications will get a specific `ZoneTableAccessor`
+  object by `ConfigurableClientList::getZoneTableAccessor()`,
+  and get an iterator object by calling `getIterator` on the accessor.
+  These are abstract classes and provide unified interfaces
+  independent from whether it's for in-memory cached zones or "real"
+  underlying data source.  But the initial implementation only
+  provides the in-memory cache version of subclass (see the next
+  item).
+
+* `ZoneTableAccessorCache`, `ZoneTableIteratorCache`: implementation
+  classes of `ZoneTableAccessor` and `ZoneTableIterator` for in-memory
+  cache.  They refer to `CacheConfig` to get a list of zones to be
+  cached.
+
+* `ZoneTableHeader`, `ZoneTable`: top-level interface to actual
+  in-memory data.  These were separated based on a prior version of
+  the design (http://bind10.isc.org/wiki/ScalableZoneLoadDesign) where
+  `ZoneTableHeader` may contain multiple `ZoneTable`s.  It's
+  one-to-one relationship in the latest version (of implementation),
+  so we could probably unify them as a cleanup.
+
+* `ZoneData`: representing the in-memory content of a single zone.
+  `ZoneTable` contains (zero, one or) multiple `ZoneData` objects.
+
+* `RdataSet`: representing the in-memory content of (data of) a single
+  RRset.
+  `ZoneData` contains `RdataSet`s corresponding to the RRsets stored
+  in the zone.
+
+* `LoadAction`: a "polymorphic" functor that implements loading zone
+  data into memory.  It hides from its user (i.e., `ZoneWriter`)
+  details about the source of the data: master file or other data
+  source (and perhaps some others).  The "polymorphism" is actually
+  realized as different implementations of the functor interface, not
+  class inheritance (but conceptually the effect and goal is the
+  same).  Note: there's a proposal to replace `LoadAction` with
+  a revised `ZoneDataLoader`, although the overall concept doesn't
+  change.  See Trac ticket #2912.
+
+* `ZoneDataLoader` and `ZoneDataUpdater`: helper classes for the
+  `LoadAction` functor(s).  These work independently from the source
+  of data, taking a sequence of RRsets objects, converting them
+  into the in-memory data structures (`RdataSet`), and installing them
+  into a newly created `ZoneData` object.
+
+Sequence for auth module using local memory segment
+---------------------------------------------------
+
+In the remaining sections, we explain how the classes shown in the
+previous section work together through their methods for commonly
+intended operations.
+
+The following sequence diagram shows the case for the authoritative
+DNS server module to maintain "local" in-memory data.  Note that
+"auth" is a conceptual "class" (not actually implemented as a C++
+class) to represent the server application behavior.  For the purpose
+of this document that should be sufficient.  The same note applies to
+all examples below.
+
+image::auth-local.png[Sequence diagram for auth server using local memory segment]
+
+1. On startup, the auth module creates a `ConfigurableClientList`
+   for each RR class specified in the configuration for "data_sources"
+   module.  It then calls `ConfigurableClientList::configure()`
+   for the given configuration of that RR class.
+
+2. For each data source, `ConfigurableClientList` creates a
+   `CacheConfig` object with the corresponding cache related
+   configuration.
+
+3. If in-memory cache is enabled for the data source,
+   `ZoneTableSegment` is also created.  In this scenario the cache
+   type is specified as "local" in the configuration, so a functor
+   creates `ZoneTableSegmentLocal` as the actual instance.
+   In this case its `ZoneTable` is immediately created, too.
+
+4. `ConfigurableClientList` checks if the created `ZoneTableSegment` is
+   writable.  It is always so for "local" type of segments.  So
+   `ConfigurableClientList` immediately loads zones to be cached into
+   memory.  For each such zone, it first gets the appropriate
+   `LoadAction` through `CacheConfig`, then creates `ZoneWriter` with
+   the `LoadAction`, and loads the data using the writer.
+
+5. If the auth module receives a "reload" command for a cached zone
+   from other module (xfrin, an end user, etc), it calls
+   `ConfigurableClientList::getCachedZoneWriter` to load and install
+   the new version of the zone.  The same loading sequence takes place
+   except that the user of the writer is the auth module.
+   Also, the old version of the zone data is destroyed at the end of
+   the process.
+
+Sequence for auth module using mapped memory segment
+----------------------------------------------------
+
+This is an example for the authoritative server module that uses
+mapped type memory segment for in-memory data.
+
+image::auth-mapped.png[Sequence diagram for auth server using mapped memory segment]
+
+1. The sequence is the same to the point of creating `CacheConfig`.
+
+2. But in this case a `ZoneTableSegmentMapped` object is created based
+   on the configuration of the cache type.  This type of
+   `ZoneTableSegment` is initially empty and isn't even associated
+   with a `MemorySegment` (and therefore considered non-writable).
+
+3. `ConfigurableClientList` checks if the zone table segment is
+   writable to know whether to load zones into memory by itself,
+   but as `ZoneTableSegment::isWritable()` returns false, it skips
+   the loading.
+
+4. The auth module gets the status of each data source, and notices
+   there's a `WAITING` state of segment. So it subscribes to the
+   "Memmgr" group on a command session and waits for an update
+   from the memory manager (memmgr) module. (See also the note at the
+   end of the section)
+
+5. When the auth module receives an update command from memmgr, it
+   calls `ConfigurableClientList::resetMemorySegment()` with the command
+   argument and the segment mode of `READ_ONLY`.
+   Note that the auth module handles the command argument as mostly
+   opaque data; it's not expected to deal with details of segment
+   type-specific behavior.
+
+6. `ConfigurableClientList::resetMemorySegment()` subsequently calls
+   `reset()` method on the corresponding `ZoneTableSegment` with the
+   given parameters.
+   In the case of `ZoneTableSegmentMapped`, it creates a new
+   `MemorySegment` object for the mapped type, which internally maps
+   the specific file into memory.
+   memmgr is expected to have prepared all necessary data in the file,
+   so all the data are immediately ready for use (i.e., there
+   shouldn't be any explicit load operation).
+
+7. When a change is made in the mapped data, memmgr will send another
+   update command with parameters for new mapping.  The auth module
+   calls `ConfigurableClientList::resetMemorySegment()`, and the
+   underlying memory segment is swapped with a new one.  The old
+   memory segment object is destroyed.  Note that
+   this "destroy" just means unmapping the memory region; the data
+   stored in the file are intact.
+
+8. If the auth module happens to receive a reload command from other
+   module, it could call
+   `ConfigurableClientList::getCachedZoneWriter()`
+   to reload the data by itself, just like in the previous section.
+   In this case, however, the writability check of
+   `getCachedZoneWriter()` fails (the segment was created as
+   `READ_ONLY` and is non-writable), so loading won't happen.
+
+NOTE: While less likely in practice, it's possible that the same auth
+module uses both "local" and "mapped" (and even others) type of
+segments for different data sources.  In such cases the sequence is
+either the one in this or previous section depending on the specified
+segment type in the configuration.  The auth module itself isn't aware
+of per segment-type details, but changes the behavior depending on the
+segment state of each data source at step 4 above: if it's `WAITING`,
+it means the auth module needs help from memmgr (that's all the auth
+module should know; it shouldn't be bothered with further details such
+as mapped file names); if it's something else, the auth module doesn't
+have to do anything further.
+
+Sequence for memmgr module initialization using mapped memory segment
+---------------------------------------------------------------------
+
+This sequence shows the common initialization sequence for the
+memory manager (memmgr) module using a mapped type memory segment.
+This is a mixture of the sequences shown in Sections 2 and 3.
+
+image::memmgr-mapped-init.png[]
+
+1. Initial sequence is the same until the application module (memmgr)
+   calls `ConfigurableClientList::getStatus()` as that for the
+   previous section.
+
+2. The memmgr module identifies the data sources whose in-memory cache
+   type is "mapped".  (Unlike other application modules, the memmgr
+   should know what such types means due to its exact responsibility).
+   For each such data source, it calls
+   `ConfigurableClientList::resetMemorySegment` with the READ_WRITE
+   mode and other mapped-type specific parameters.  memmgr should be
+   able to generate the parameters from its own configuration and
+   other data source specific information (such as the RR class and
+   data source name).
+
+3. The `ConfigurableClientList` class calls
+   `ZoneTableSegment::reset()` on the corresponding zone table
+   segment with the given parameters.  In this case, since the mode is
+   READ_WRITE, a new `ZoneTable` will be created (assuming this is a
+   very first time initialization; if there's already a zone table
+   in the segment, it will be used).
+
+4. The memmgr module then calls
+   `ConfigurableClientList::getZoneTableAccessor()`, and calls the
+   `getItertor()` method on it to get a list of zones for which
+   zone data are to be loaded into the memory segment.
+
+5. The memmgr module loads the zone data for each such zone.  This
+   sequence is the same as shown in Section 2.
+
+6. On loading all zone data, the memmgr module sends an update command
+   to all interested modules (such as auth) in the segment, and waits
+   for acknowledgment from all of them.
+
+7. Then it calls `ConfigurableClientList::resetMemorySegment()` for
+   this data source with almost the same parameter as step 2 above,
+   but with a different mapped file name.  This will make a swap of
+   the underlying memory segment with a new mapping.  The old
+   `MemorySegment` object will be destroyed, but as explained in the
+   previous section, it simply means unmapping the file.
+
+8. The memmgr loads the zone data into the newly mapped memory region
+   by repeating the sequence shown in step 5.
+
+9. The memmgr repeats all this sequence for data sources that use
+   "mapped" segment for in-memory cache.  Note: it could handle
+   multiple data sources in parallel, e.g., while waiting for
+   acknowledgment from other modules.
+
+Sequence for memmgr module to reload a zone using mapped memory segment
+-----------------------------------------------------------------------
+
+This example is a continuation of the previous section, describing how
+the memory manager reloads a zone in mapped memory segment.
+
+image::memmgr-mapped-reload.png[]
+
+1. When the memmgr module receives a reload command from other module,
+   it calls `ConfigurableClientList::getCachedZoneWriter()` for the
+   specified zone name.  This method checks the writability of
+   the segment, and since it's writable (as memmgr created it in the
+   READ_WRITE mode), `getCachedZoneWriter()` succeeds and returns
+   a `ZoneWriter`.
+
+2. The memmgr module uses the writer to load the new version of zone
+   data.  There is nothing specific to mapped-type segment here.
+
+3. The memmgr module then sends an update command to other modules
+   that would share this version, and waits for acknowledgment from
+   all of them.
+
+4. On getting acknowledgments, the memmgr module calls
+  `ConfigurableClientList::resetMemorySegment()` with the parameter
+   specifying the other mapped file.  This will swap the underlying
+   `MemorySegment` with a newly created one, mapping the other file.
+
+5. The memmgr updates this segment, too, so the two files will contain
+   the same version of data.

+ 132 - 0
doc/design/datasrc/memmgr-mapped-init.txt

@@ -0,0 +1,132 @@
+@startuml
+
+participant memmgr as "memmgr"
+[-> memmgr: new/initial config\n(datasrc cfg)
+activate memmgr
+
+participant list as "Configurable\nClientList"
+create list
+memmgr -> list: <<construct>>
+
+memmgr -> list: configure(cfg)
+activate list
+
+create CacheConfig
+list -> CacheConfig: <<construct>> (cfg)
+
+participant zt_segment as "ZoneTable\nSegment\n(Mapped)"
+create zt_segment
+list -> zt_segment: <<construct>>
+
+list -> zt_segment: isWritable()
+activate zt_segment
+note over zt_segment: Segment not writable\nwhen not reset
+zt_segment --> list: false
+deactivate zt_segment
+
+deactivate list
+
+memmgr -> list: getStatus()
+activate list
+list --> memmgr: DataSourceStatus[]
+deactivate list
+
+loop for each datasrc with mapped segment
+
+memmgr -> list: resetMemorySegment\n(datasrc_name,\nREAD_WRITE,\nsegmentparam)
+activate list
+
+list -> zt_segment: reset\n(READ_WRITE,\nsegmentparam)
+activate zt_segment
+
+participant segment as "Memory\nSegment\n(Mapped)"
+create segment
+zt_segment -> segment: <<construct>>
+
+participant segment.2 as "Memory\nSegment\n(Mapped)\n2"
+
+create ZoneTable
+zt_segment -> ZoneTable: <<construct>>
+
+deactivate zt_segment
+deactivate list
+
+memmgr -> list: getZoneTableAccessor\n(datasrc_name,\ncache=true)
+activate list
+list -> memmgr: ZoneTableAccessor
+deactivate list
+
+
+loop for each zone given by ZoneTableIterator
+
+memmgr -> list: getCachedZoneWriter\n(zone_name)
+activate list
+
+list -> CacheConfig: getLoadAction()
+activate CacheConfig
+
+create LoadAction
+CacheConfig -> LoadAction: <<construct>>
+
+CacheConfig --> list : LoadAction
+
+deactivate CacheConfig
+
+create ZoneWriter
+list -> ZoneWriter: <<construct>> (load_action)
+
+list --> memmgr: ZoneWriter
+
+deactivate list
+
+
+memmgr -> ZoneWriter: load()
+activate ZoneWriter
+ZoneWriter -> LoadAction: (funcall)
+activate LoadAction
+
+create ZoneData
+LoadAction -> ZoneData: <<construct>> via helpers
+
+LoadAction --> ZoneWriter: ZoneData
+deactivate LoadAction
+deactivate ZoneWriter
+
+memmgr -> ZoneWriter: install()
+activate ZoneWriter
+
+ZoneWriter -> ZoneTable: addZone(ZoneData)
+activate ZoneTable
+ZoneTable --> ZoneWriter: NULL (no old data)
+deactivate ZoneTable
+
+deactivate ZoneWriter
+
+end
+
+[<- memmgr: command to\nmodules\n(datasrc_name,\nsegmentparam)
+[--> memmgr: ack from all\nmodules
+
+memmgr -> list: resetMemorySegment\n(datasrc_name,\nREAD_WRITE,\nsegmentparam)
+activate list
+
+list -> zt_segment: reset\n(READ_WRITE,\nsegmentparam)
+activate zt_segment
+
+zt_segment -> segment: <<destroy>>
+destroy segment
+create segment.2
+zt_segment -> segment.2: <<construct>>
+
+deactivate zt_segment
+deactivate list
+
+note left of memmgr: load zone\nfor each zone\ngiven by\nZoneTableIterator
+
+end
+
+[<-- memmgr
+
+deactivate memmgr
+
+@enduml

+ 92 - 0
doc/design/datasrc/memmgr-mapped-reload.txt

@@ -0,0 +1,92 @@
+@startuml
+
+participant memmgr as "memmgr"
+[-> memmgr: reload\n(zonename)
+activate memmgr
+
+participant list as "Configurable\nClientList"
+memmgr -> list: getCachedZoneWriter\n(zone_name)
+activate list
+
+participant CacheConfig
+
+participant zt_segment as "ZoneTable\nSegment\n(Mapped)"
+participant segment as "Memory\nSegment\n(Mapped)"
+participant segment.2 as "Memory\nSegment\n(Mapped)\n2"
+
+list -> zt_segment: isWritable()
+activate zt_segment
+zt_segment --> list: true
+deactivate zt_segment
+
+list -> CacheConfig: getLoadAction()
+activate CacheConfig
+
+participant ZoneTable
+participant ZoneWriter
+
+create LoadAction
+CacheConfig -> LoadAction: <<construct>>
+CacheConfig --> list: LoadAction
+deactivate CacheConfig
+
+create ZoneWriter
+list -> ZoneWriter: <<construct>> (LoadAction)
+list --> memmgr: ZoneWriter
+deactivate list
+
+memmgr -> ZoneWriter: load()
+activate ZoneWriter
+ZoneWriter -> LoadAction: (funcall)
+activate LoadAction
+
+participant ZoneData
+
+create ZoneData.2
+LoadAction -> ZoneData.2: <<construct>> via helpers
+
+LoadAction --> ZoneWriter: ZoneData.2
+deactivate LoadAction
+deactivate ZoneWriter
+
+memmgr -> ZoneWriter: install()
+activate ZoneWriter
+
+ZoneWriter -> ZoneTable: addZone(ZoneData.2)
+activate ZoneTable
+ZoneTable --> ZoneWriter: ZoneData (old data)
+deactivate ZoneTable
+
+deactivate ZoneWriter
+
+memmgr -> ZoneWriter: cleanup()
+activate ZoneWriter
+
+ZoneWriter -> ZoneData: <<destroy>>
+destroy ZoneData
+deactivate ZoneWriter
+
+[<- memmgr: command to\nmodules\n(datasrc_name,\nsegmentparam)
+[--> memmgr: ack from all\nmodules
+
+memmgr -> list: resetMemorySegment\n(datasrc_name,\nREAD_WRITE,\nsegmentparam)
+activate list
+
+list -> zt_segment: reset\n(READ_WRITE,\nsegmentparam)
+activate zt_segment
+
+zt_segment -> segment: <<destroy>>
+destroy segment
+create segment.2
+zt_segment -> segment.2: <<construct>>
+
+deactivate zt_segment
+deactivate list
+
+note left of memmgr: (repeat the\nsame sequence\nfor loading to the\nother segment)
+
+memmgr -> list: getCachedZoneWriter\n(zone_name)
+
+...
+
+@enduml

+ 68 - 0
doc/design/datasrc/overview.txt

@@ -0,0 +1,68 @@
+@startuml
+
+hide members
+
+note "Automatic placement of classes\ndoesn't look good. This diagram\nhas to be improved." as n1
+
+Auth "1" *-d-> "*" ConfigurableClientList
+Auth -d-> DataSourceClient
+Auth -d-> ZoneWriter
+Auth -d-> ZoneTableAccessor
+Auth -d-> DataSourceStatus
+Auth -d-> ZoneTableIterator
+
+ConfigurableClientList "1" *-d-> "*" DataSourceInfo
+ConfigurableClientList ..> ZoneTableSegment : <<reset>>
+ConfigurableClientList ..d-> DataSourceStatus : <<create>>
+ConfigurableClientList ..> ZoneWriter : <<create>>
+ConfigurableClientList ..> ZoneTableAccessor : <<create>>
+
+DataSourceInfo "1" *-u-> "*" DataSourceClient
+DataSourceInfo "1" *-r-> "*" CacheConfig
+DataSourceInfo "1" *-d-> "*" ZoneTableSegment
+
+ZoneTableAccessor ..> ZoneTableIterator : <<create>>
+
+ZoneTableAccessorCache -> CacheConfig
+ZoneTableAccessorCache ..> ZoneTableIteratorCache : <<create>>
+ZoneTableAccessorCache -u-o ZoneTableAccessor
+
+ZoneTableIteratorCache -u-o ZoneTableIterator
+ZoneTableIteratorCache -u-> CacheConfig
+
+ZoneWriter -d-> ZoneTableSegment
+ZoneWriter ..> ZoneData : add/replace
+
+ZoneTableSegment "1" *-r-> "1" ZoneTableHeader
+ZoneTableSegment "1" *-d-> "1" MemorySegment
+
+CacheConfig ..> LoadAction
+
+LoadAction ..> ZoneData : create
+LoadAction *-> ZoneDataLoader
+
+ZoneDataLoader -> ZoneData
+ZoneDataLoader *-> ZoneDataUpdater
+ZoneDataLoader -> MemorySegment
+
+ZoneDataUpdater -> ZoneData
+ZoneDataUpdater ..> RdataSet : create
+ZoneDataUpdater ..> RdataSet : add
+
+ZoneTableHeader "1" *-d-> "1" ZoneTable
+ZoneTable "1" *-d-> "1" ZoneData
+ZoneData "1" *-d-> "1" RdataSet
+
+loadFromFile -d-o LoadAction
+IteratorLoader -d-o LoadAction
+
+MemorySegmentMapped -d-o MemorySegment
+MemorySegmentLocal -d-o MemorySegment
+
+ZoneTableSegmentMapped -d-o ZoneTableSegment
+ZoneTableSegmentLocal -d-o ZoneTableSegment
+
+ZoneTableSegmentMapped *-d-> MemorySegmentMapped
+ZoneTableSegmentLocal *-d-> MemorySegmentLocal
+
+@enduml