Rev 3639: Improve inventory design docs with current planning thoughts. in http://people.ubuntu.com/~robertc/baz2.0/inventory
Robert Collins
robertc at robertcollins.net
Tue Aug 19 02:35:18 BST 2008
At http://people.ubuntu.com/~robertc/baz2.0/inventory
------------------------------------------------------------
revno: 3639
revision-id: robertc at robertcollins.net-20080819013507-bc7a4529lw8ze9b5
parent: pqm at pqm.ubuntu.com-20080816000954-t0401ff8s3ydnkr6
committer: Robert Collins <robertc at robertcollins.net>
branch nick: inventory
timestamp: Tue 2008-08-19 11:35:07 +1000
message:
Improve inventory design docs with current planning thoughts.
modified:
doc/developers/inventory.txt inventory.txt-20080103013957-opkrhxy6lmywmx4i-1
=== modified file 'doc/developers/inventory.txt'
--- a/doc/developers/inventory.txt 2008-01-03 01:40:16 +0000
+++ b/doc/developers/inventory.txt 2008-08-19 01:35:07 +0000
@@ -8,7 +8,9 @@
========
Inventories provide an abstraction for talking about the shape of a tree.
-Generally only tree object implementors should be concerned about inventories.
+Generally only tree object implementors should be concerned about entire
+inventory objects and their implementation. Other common exceptions are
+full-tree operations such as 'checkout', 'export' and 'import'.
In memory inventories
=====================
@@ -39,9 +41,141 @@
All the xml serialized forms write to and read from a single byte string, whose
hash is then the inventory validator for the commit object.
-journalled
-----------
-
-The in development journalled inventory serializer generates a single byte
-string during serialization, but may require many byte strings to deserialize,
-and these are discovered recursively.
+
+Serialization scaling and future designs
+========================================
+
+Overall efficiency and scaling is constrained by the bottom level structure
+that an inventory is stored as. We have a number of goals we want to achieve:
+
+ 1. Allow commit to write less than the full tree's data in to the repository
+ in the general case.
+ 2. Allow the data that is written to be calculated without examining every
+ versioned path in the tree.
+ 3. Generate the exact same representation for a given inventory regardless of
+ the amount of history available.
+ 4. Allow in memory deltas to be generated directly from the serialised form
+ without upcasting to a full in-memory representation or examining every
+ path in the tree. Ideally the work performed will be proportional to the
+ amount of changes between the trees being compared.
+ 5. Allow fetch to determine the file texts that need to be pulled to ensure
+ that the entire tree can be reconstructed without having to probe every
+ path in the tree.
+ 6. Allow bzr map paths to file ids without reading the entire serialised
+ form. This is something that is used by commands such as merge PATH and
+ diff -r X PATH.
+ 7. Let bzr map file ids to paths without reading the entire serialised form.
+ This is used by commands that are presenting output to the user such as
+ loggerhed, bzr-search, log FILENAME.
+ 8. We want a strong validator for inventories which is cheap to generate.
+ Specifically we should be able to create the generator for a new commit
+ without processing all the data of the basis commit.
+ 9. Testaments generation is currently size(tree), we would like to create a
+ new testament standard which requires less work so that signed commits
+ are not significantly slower than regular commits.
+
+
+We have current performance and memory bugs in log -v, merge, commit, diff -r,
+loggerhead and status -r which can be addresessed by an inventory system
+meeting these goals.
+
+Current situation
+-----------------
+
+The xml based implementation we use today layers the inventory as a bytestring
+which is stored under a single key; the bytestring is then compressed as a
+delta against the bytestring of its left hand parent by the knit code.
+
+Gap analysis:
+
+ 1. Succeeds
+ 2. Fails - generating a new xml representation needs full tree data.
+ 3. Succeeds - the inventory layer accesses the bytestring, which is
+ deterministic
+ 4. Fails - we have to reconstruct both inventories as trees and then delta
+ the resulting in memory objects.
+ 5. Partial success - the revision field in the inventory can be scanned for
+ in both text-delta and full-bytestring form; other revision values than
+ those revisions which are being pulled are by definition absent.
+ 6. Partially succeeds - with appropriate logic a path<->id map can be generated
+ just-in-time, but it is complex and still requires reconstructing the
+ entire byte-string.
+ 7. As for 6.
+ 8. Fails - we have to hash the entire tree in serialised form to generate
+ validators.
+ 9. Fails.
+
+Long term work
+--------------
+
+Some things are likely harder to fix incrementally than others. In particular,
+goal 3 (constant canonical form) is arguably only achieved if we remove all
+derived data such as the last-modified revision from the inventory itself. That
+said, the last-modified appears to be in a higher level than raw serialization.
+So in the medium term we will not alter the contents of inventories, only the
+way that the current contents are mapped to and from disk.
+
+
+Layering
+--------
+
+We desire clear and clean layers. Each layer should be as simple as we can make
+it to aid in debugging and performance tuning. So where we can choose to either
+write a complex layer and something simple on top of it, or two layers with
+neither being as complex - then we should consider the latter choice better in
+the absence of compelling reasons not to.
+
+Some key layers we have today and can look at using or tweaking are:
+
+ * Tree objects - the abstract interface bzrlib code works in
+ * VersionedFiles - the optionally delta compressing key->bytes storage
+ interface.
+ * Inventory - the abstract interface that many tree operations are written in.
+
+These layers are probably sufficient with minor tweaking. We may want to add
+additional modules/implementations of one or more layers, but that doesn't
+really require new layers to be exposed.
+
+Design elements to achieve the goals in a future inventory implementation
+-------------------------------------------------------------------------
+
+ * Split up the logical document into smaller serialised fragements. For
+ instance hash buckets or nodes in a tree of some sort. By serialising in
+ smaller units, we can increase the number of smaller units rather than
+ their size as the tree grows; as long as two similar trees have similar
+ serialised forms, the amount of different content should be quite high.
+
+ * Use fragment identifiers that are independent of revision id, so that
+ serialisation of two related trees generates overlap in the keyspace
+ for fragments without requiring explicit delta logic. Content Hash Keys
+ (e.g. ('sha1:ABCDEF0123456789...',) are useful here because of the ability
+ to assign them without reference to history.)
+
+ * Store the fragments in our existing VersionedFiles store. Adding an index
+ for them. Have the serialised form be uncompressed utf8, so that delta logic
+ in the VersionedFiles layer can be used. We may need to provide some sort
+ of hinting mechanism to get good compression - but the trivially available
+ zlib compression of knits-with-no-deltas is probably a good start.
+
+ * Item_keys_introduced_by is innately a history-using function; we can
+ reproduce the text-key finding logic by doing a tree diff between any tree
+ and and older tree - that will limit the amount of data we need to process
+ to something proportional to the difference and the size of each fragment.
+ When checking many versions we can track which fragments we have examined
+ and only look at new unique ones as each version is examined in turn.
+
+ * Working tree to arbitrary history revision deltas/comparisons can be scaled
+ up by doing a two-step (fixed at two!) delta combining - delta(tree, basis)
+ and then combine that with delta(basis, arbitrary_revision) using the
+ repositories ability to get a delta cheaply.
+
+ * The key primitives we need seem to be:
+ * canonical_form(inventory) -> fragments
+ * delta(inventory, inventory) -> inventory_delta
+ * apply(inventory_delta, canonical_form) -> fragments
+
+ * Having very many small fragments is likely to cause a high latency
+ multiplier unless we are careful.
+
+ * Possible designs to investigate - a hash bucket approach, radix trees,
+ B+ trees, directory trees (with splits inside a directory?).
More information about the bazaar-commits
mailing list