From b99653a9d3d231a9e1e4a1ddca41a08b3b733ae9 Mon Sep 17 00:00:00 2001 From: Máximo Cuadros Date: Mon, 19 Nov 2018 15:40:26 +0100 Subject: plumbing: format/index: support for EOIE extension, by default on git v2.2.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Máximo Cuadros --- plumbing/format/index/decoder.go | 25 ++++++++++++++ plumbing/format/index/decoder_test.go | 16 +++++++++ plumbing/format/index/doc.go | 61 ++++++++++++++++++++++++++++++++++- plumbing/format/index/index.go | 24 ++++++++++++-- 4 files changed, 122 insertions(+), 4 deletions(-) (limited to 'plumbing') diff --git a/plumbing/format/index/decoder.go b/plumbing/format/index/decoder.go index df25530..ac57d08 100644 --- a/plumbing/format/index/decoder.go +++ b/plumbing/format/index/decoder.go @@ -261,6 +261,17 @@ func (d *Decoder) readExtension(idx *Index, header []byte) error { if err := d.Decode(idx.ResolveUndo); err != nil { return err } + case bytes.Equal(header, endOfIndexEntryExtSignature): + r, err := d.getExtensionReader() + if err != nil { + return err + } + + idx.EndOfIndexEntry = &EndOfIndexEntry{} + d := &endOfIndexEntryDecoder{r} + if err := d.Decode(idx.EndOfIndexEntry); err != nil { + return err + } default: return errUnknownExtension } @@ -449,3 +460,17 @@ func (d *resolveUndoDecoder) readStage(e *ResolveUndoEntry, s Stage) error { return nil } + +type endOfIndexEntryDecoder struct { + r io.Reader +} + +func (d *endOfIndexEntryDecoder) Decode(e *EndOfIndexEntry) error { + var err error + e.Offset, err = binary.ReadUint32(d.r) + if err != nil { + return err + } + + return binary.Read(d.r, &e.Hash) +} diff --git a/plumbing/format/index/decoder_test.go b/plumbing/format/index/decoder_test.go index b612ebb..7468ad0 100644 --- a/plumbing/format/index/decoder_test.go +++ b/plumbing/format/index/decoder_test.go @@ -202,3 +202,19 @@ func (s *IndexSuite) TestDecodeV4(c *C) { c.Assert(idx.Entries[6].IntentToAdd, Equals, true) c.Assert(idx.Entries[6].SkipWorktree, Equals, false) } + +func (s *IndexSuite) TestDecodeEndOfIndexEntry(c *C) { + f, err := fixtures.Basic().ByTag("end-of-index-entry").One().DotGit().Open("index") + c.Assert(err, IsNil) + defer func() { c.Assert(f.Close(), IsNil) }() + + idx := &Index{} + d := NewDecoder(f) + err = d.Decode(idx) + c.Assert(err, IsNil) + + c.Assert(idx.Version, Equals, uint32(2)) + c.Assert(idx.EndOfIndexEntry, NotNil) + c.Assert(idx.EndOfIndexEntry.Offset, Equals, uint32(716)) + c.Assert(idx.EndOfIndexEntry.Hash.String(), Equals, "922e89d9ffd7cefce93a211615b2053c0f42bd78") +} diff --git a/plumbing/format/index/doc.go b/plumbing/format/index/doc.go index d1e7b33..f2b3d76 100644 --- a/plumbing/format/index/doc.go +++ b/plumbing/format/index/doc.go @@ -297,5 +297,64 @@ // in the previous ewah bitmap. // // - One NUL. -// Source https://www.kernel.org/pub/software/scm/git/docs/technical/index-format.txt +// +// == File System Monitor cache +// +// The file system monitor cache tracks files for which the core.fsmonitor +// hook has told us about changes. The signature for this extension is +// { 'F', 'S', 'M', 'N' }. +// +// The extension starts with +// +// - 32-bit version number: the current supported version is 1. +// +// - 64-bit time: the extension data reflects all changes through the given +// time which is stored as the nanoseconds elapsed since midnight, +// January 1, 1970. +// +// - 32-bit bitmap size: the size of the CE_FSMONITOR_VALID bitmap. +// +// - An ewah bitmap, the n-th bit indicates whether the n-th index entry +// is not CE_FSMONITOR_VALID. +// +// == End of Index Entry +// +// The End of Index Entry (EOIE) is used to locate the end of the variable +// length index entries and the begining of the extensions. Code can take +// advantage of this to quickly locate the index extensions without having +// to parse through all of the index entries. +// +// Because it must be able to be loaded before the variable length cache +// entries and other index extensions, this extension must be written last. +// The signature for this extension is { 'E', 'O', 'I', 'E' }. +// +// The extension consists of: +// +// - 32-bit offset to the end of the index entries +// +// - 160-bit SHA-1 over the extension types and their sizes (but not +// their contents). E.g. if we have "TREE" extension that is N-bytes +// long, "REUC" extension that is M-bytes long, followed by "EOIE", +// then the hash would be: +// +// SHA-1("TREE" + + +// "REUC" + ) +// +// == Index Entry Offset Table +// +// The Index Entry Offset Table (IEOT) is used to help address the CPU +// cost of loading the index by enabling multi-threading the process of +// converting cache entries from the on-disk format to the in-memory format. +// The signature for this extension is { 'I', 'E', 'O', 'T' }. +// +// The extension consists of: +// +// - 32-bit version (currently 1) +// +// - A number of index offset entries each consisting of: +// +// - 32-bit offset from the begining of the file to the first cache entry +// in this block of entries. +// +// - 32-bit count of cache entries in this blockpackage index package index diff --git a/plumbing/format/index/index.go b/plumbing/format/index/index.go index fc7b8cd..6c4b7ca 100644 --- a/plumbing/format/index/index.go +++ b/plumbing/format/index/index.go @@ -18,9 +18,10 @@ var ( // ErrEntryNotFound is returned by Index.Entry, if an entry is not found. ErrEntryNotFound = errors.New("entry not found") - indexSignature = []byte{'D', 'I', 'R', 'C'} - treeExtSignature = []byte{'T', 'R', 'E', 'E'} - resolveUndoExtSignature = []byte{'R', 'E', 'U', 'C'} + indexSignature = []byte{'D', 'I', 'R', 'C'} + treeExtSignature = []byte{'T', 'R', 'E', 'E'} + resolveUndoExtSignature = []byte{'R', 'E', 'U', 'C'} + endOfIndexEntryExtSignature = []byte{'E', 'O', 'I', 'E'} ) // Stage during merge @@ -50,6 +51,8 @@ type Index struct { Cache *Tree // ResolveUndo represents the 'Resolve undo' extension ResolveUndo *ResolveUndo + // EndOfIndexEntry represents the 'End of Index Entry' extension + EndOfIndexEntry *EndOfIndexEntry } // Add creates a new Entry and returns it. The caller should first check that @@ -193,3 +196,18 @@ type ResolveUndoEntry struct { Path string Stages map[Stage]plumbing.Hash } + +// EndOfIndexEntry is the End of Index Entry (EOIE) is used to locate the end of +// the variable length index entries and the begining of the extensions. Code +// can take advantage of this to quickly locate the index extensions without +// having to parse through all of the index entries. +// +// Because it must be able to be loaded before the variable length cache +// entries and other index extensions, this extension must be written last. +type EndOfIndexEntry struct { + // Offset to the end of the index entries + Offset uint32 + // Hash is a SHA-1 over the extension types and their sizes (but not + // their contents). + Hash plumbing.Hash +} -- cgit