2
This code is derived from jgit (http://eclipse.org/jgit).
3
Copyright owners are documented in jgit's IP log.
5
This program and the accompanying materials are made available
6
under the terms of the Eclipse Distribution License v1.0 which
7
accompanies this distribution, is reproduced below, and is
8
available at http://www.eclipse.org/org/documents/edl-v10.php
12
Redistribution and use in source and binary forms, with or
13
without modification, are permitted provided that the following
16
- Redistributions of source code must retain the above copyright
17
notice, this list of conditions and the following disclaimer.
19
- Redistributions in binary form must reproduce the above
20
copyright notice, this list of conditions and the following
21
disclaimer in the documentation and/or other materials provided
22
with the distribution.
24
- Neither the name of the Eclipse Foundation, Inc. nor the
25
names of its contributors may be used to endorse or promote
26
products derived from this software without specific prior
29
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51
/// <summary>A note tree holding only notes, with no subtrees.</summary>
53
/// A note tree holding only notes, with no subtrees.
54
/// The leaf bucket contains on average less than 256 notes, all of whom share
55
/// the same leading prefix. If a notes branch has less than 256 notes, the top
56
/// level tree of the branch should be a LeafBucket. Once a notes branch has more
57
/// than 256 notes, the root should be a
58
/// <see cref="FanoutBucket">FanoutBucket</see>
59
/// and the LeafBucket
60
/// will appear only as a cell of a FanoutBucket.
61
/// Entries within the LeafBucket are stored sorted by ObjectId, and lookup is
62
/// performed using binary search. As the entry list should contain fewer than
63
/// 256 elements, the average number of compares to find an element should be
64
/// less than 8 due to the O(log N) lookup behavior.
65
/// A LeafBucket must be parsed from a tree object by
66
/// <see cref="NoteParser">NoteParser</see>
69
internal class LeafBucket : InMemoryNoteBucket
71
internal const int MAX_SIZE = 256;
73
/// <summary>All note blobs in this bucket, sorted sequentially.</summary>
74
/// <remarks>All note blobs in this bucket, sorted sequentially.</remarks>
78
/// Number of items in
79
/// <see cref="notes">notes</see>
84
internal LeafBucket(int prefixLen) : base(prefixLen)
89
private int Search(AnyObjectId objId)
95
int mid = (int)(((uint)(low + high)) >> 1);
96
int cmp = objId.CompareTo(notes[mid]);
116
internal override Note GetNote(AnyObjectId objId, ObjectReader or)
118
int idx = Search(objId);
119
return 0 <= idx ? notes[idx] : null;
122
internal virtual Note Get(int index)
127
internal virtual int Size()
132
internal override Sharpen.Iterator<Note> Iterator(AnyObjectId objId, ObjectReader
135
return new _Iterator_121(this);
138
private sealed class _Iterator_121 : Sharpen.Iterator<Note>
140
public _Iterator_121(LeafBucket _enclosing)
142
this._enclosing = _enclosing;
147
public override bool HasNext()
149
return this.idx < this._enclosing.cnt;
152
public override Note Next()
156
return this._enclosing.notes[this.idx++];
160
throw new NoSuchElementException();
164
public override void Remove()
166
throw new NotSupportedException();
169
private readonly LeafBucket _enclosing;
172
/// <exception cref="System.IO.IOException"></exception>
173
internal override int EstimateSize(AnyObjectId noteOn, ObjectReader or)
178
/// <exception cref="System.IO.IOException"></exception>
179
internal override InMemoryNoteBucket Set(AnyObjectId noteOn, AnyObjectId noteData
182
int p = Search(noteOn);
185
if (noteData != null)
187
notes[p].SetData(noteData.Copy());
192
System.Array.Copy(notes, p + 1, notes, p, cnt - p - 1);
194
return 0 < cnt ? this : null;
199
if (noteData != null)
203
return Split().Set(noteOn, noteData, or);
211
System.Array.Copy(notes, p, notes, p + 1, cnt - p);
213
notes[p] = new Note(noteOn, noteData.Copy());
225
/// <exception cref="System.IO.IOException"></exception>
226
internal override ObjectId WriteTree(ObjectInserter inserter)
228
return inserter.Insert(Build());
231
internal override ObjectId GetTreeId()
233
return new ObjectInserter.Formatter().IdFor(Build());
236
private TreeFormatter Build()
238
byte[] nameBuf = new byte[Constants.OBJECT_ID_STRING_LENGTH];
239
int nameLen = Constants.OBJECT_ID_STRING_LENGTH - prefixLen;
240
TreeFormatter fmt = new TreeFormatter(TreeSize(nameLen));
241
NonNoteEntry e = nonNotes;
242
for (int i = 0; i < cnt; i++)
245
n.CopyTo(nameBuf, 0);
246
while (e != null && e.PathCompare(nameBuf, prefixLen, nameLen, FileMode.REGULAR_FILE
252
fmt.Append(nameBuf, prefixLen, nameLen, FileMode.REGULAR_FILE, n.GetData());
254
for (; e != null; e = e.next)
261
private int TreeSize(int nameLen)
263
int sz = cnt * TreeFormatter.EntrySize(FileMode.REGULAR_FILE, nameLen);
264
for (NonNoteEntry e = nonNotes; e != null; e = e.next)
266
sz += e.TreeEntrySize();
271
internal virtual void ParseOneEntry(AnyObjectId noteOn, AnyObjectId noteData)
274
notes[cnt++] = new Note(noteOn, noteData.Copy());
277
internal override InMemoryNoteBucket Append(Note note)
281
return Split().Append(note);
291
private void GrowIfFull()
293
if (notes.Length == cnt)
295
Note[] n = new Note[notes.Length * 2];
296
System.Array.Copy(notes, 0, n, 0, cnt);
301
private bool ShouldSplit()
303
return MAX_SIZE <= cnt && prefixLen + 2 < Constants.OBJECT_ID_STRING_LENGTH;
306
internal virtual FanoutBucket Split()
308
FanoutBucket n = new FanoutBucket(prefixLen);
309
for (int i = 0; i < cnt; i++)
313
n.nonNotes = nonNotes;