59
unsigned int n);
60
61
/*
62
- * To find a leaf_node:
62
+ * Search the tree until the appropriate location for the given key is found:
63
* 1. Start at the root node, with n = 0
64
- * 2. Use the nth nibble of the key as an index into a:
65
- * - If a[n] is an int_node, recurse into that node and increment n
66
- * - If a leaf_node with matching key, return leaf_node (assert note entry)
64
+ * 2. If a[0] at the current level is a matching subtree entry, unpack that
65
+ * subtree entry and remove it; restart search at the current level.
66
+ * 3. Use the nth nibble of the key as an index into a:
67
+ * - If a[n] is an int_node, recurse from #2 into that node and increment n
68
* - If a matching subtree entry, unpack that subtree entry (and remove it);
69
* restart search at the current level.
69
- * - Otherwise, we end up at a NULL pointer, or a non-matching leaf_node.
70
- * Backtrack out of the recursion, one level at a time and check a[0]:
71
- * - If a[0] at the current level is a matching subtree entry, unpack that
72
- * subtree entry (and remove it); restart search at the current level.
70
+ * - Otherwise, we have found one of the following:
71
+ * - a subtree entry which does not match the key
72
+ * - a note entry which may or may not match the key
73
+ * - an unused leaf node (NULL)
74
+ * In any case, set *tree and *n, and return pointer to the tree location.
75
*/
74
-static struct leaf_node *note_tree_find(struct int_node *tree, unsigned char n,
75
- const unsigned char *key_sha1)
76
+static void **note_tree_search(struct int_node **tree,
77
+ unsigned char *n, const unsigned char *key_sha1)
78
{
79
struct leaf_node *l;
78
- unsigned char i = GET_NIBBLE(n, key_sha1);
79
- void *p = tree->a[i];
80
+ unsigned char i;
81
+ void *p = (*tree)->a[0];
82
83
+ if (GET_PTR_TYPE(p) == PTR_TYPE_SUBTREE) {
84
+ l = (struct leaf_node *) CLR_PTR_TYPE(p);
85
+ if (!SUBTREE_SHA1_PREFIXCMP(key_sha1, l->key_sha1)) {
86
+ /* unpack tree and resume search */
87
+ (*tree)->a[0] = NULL;
88
+ load_subtree(l, *tree, *n);
89
+ free(l);
90
+ return note_tree_search(tree, n, key_sha1);
91
+ }
92
+ }
93
+
94
+ i = GET_NIBBLE(*n, key_sha1);
95
+ p = (*tree)->a[i];
96
switch(GET_PTR_TYPE(p)) {
97
case PTR_TYPE_INTERNAL:
83
- l = note_tree_find(CLR_PTR_TYPE(p), n + 1, key_sha1);
84
- if (l)
85
- return l;
86
- break;
87
- case PTR_TYPE_NOTE:
88
- l = (struct leaf_node *) CLR_PTR_TYPE(p);
89
- if (!hashcmp(key_sha1, l->key_sha1))
90
- return l; /* return note object matching given key */
91
- break;
98
+ *tree = CLR_PTR_TYPE(p);
99
+ (*n)++;
100
+ return note_tree_search(tree, n, key_sha1);
101
case PTR_TYPE_SUBTREE:
102
l = (struct leaf_node *) CLR_PTR_TYPE(p);
103
if (!SUBTREE_SHA1_PREFIXCMP(key_sha1, l->key_sha1)) {
104
/* unpack tree and resume search */
96
- tree->a[i] = NULL;
97
- load_subtree(l, tree, n);
105
+ (*tree)->a[i] = NULL;
106
+ load_subtree(l, *tree, *n);
107
free(l);
99
- return note_tree_find(tree, n, key_sha1);
108
+ return note_tree_search(tree, n, key_sha1);
109
}
101
- break;
102
- case PTR_TYPE_NULL:
110
+ /* fall through */
111
default:
104
- assert(!p);
105
- break;
112
+ return &((*tree)->a[i]);
113
}
114
+}
115
108
- /*
109
- * Did not find key at this (or any lower) level.
110
- * Check if there's a matching subtree entry in tree->a[0].
111
- * If so, unpack tree and resume search.
112
- */
113
- p = tree->a[0];
114
- if (GET_PTR_TYPE(p) != PTR_TYPE_SUBTREE)
115
- return NULL;
116
- l = (struct leaf_node *) CLR_PTR_TYPE(p);
117
- if (!SUBTREE_SHA1_PREFIXCMP(key_sha1, l->key_sha1)) {
118
- /* unpack tree and resume search */
119
- tree->a[0] = NULL;
120
- load_subtree(l, tree, n);
121
- free(l);
122
- return note_tree_find(tree, n, key_sha1);
116
+/*
117
+ * To find a leaf_node:
118
+ * Search to the tree location appropriate for the given key:
119
+ * If a note entry with matching key, return the note entry, else return NULL.
120
+ */
121
+static struct leaf_node *note_tree_find(struct int_node *tree, unsigned char n,
122
+ const unsigned char *key_sha1)
123
+{
124
+ void **p = note_tree_search(&tree, &n, key_sha1);
125
+ if (GET_PTR_TYPE(*p) == PTR_TYPE_NOTE) {
126
+ struct leaf_node *l = (struct leaf_node *) CLR_PTR_TYPE(*p);
127
+ if (!hashcmp(key_sha1, l->key_sha1))
128
+ return l;
129
}
130
return NULL;
131
}
132
133
+/* Create a new blob object by concatenating the two given blob objects */
134
+static int concatenate_notes(unsigned char *cur_sha1,
135
+ const unsigned char *new_sha1)
136
+{
137
+ char *cur_msg, *new_msg, *buf;
138
+ unsigned long cur_len, new_len, buf_len;
139
+ enum object_type cur_type, new_type;
140
+ int ret;
141
+
142
+ /* read in both note blob objects */
143
+ new_msg = read_sha1_file(new_sha1, &new_type, &new_len);
144
+ if (!new_msg || !new_len || new_type != OBJ_BLOB) {
145
+ free(new_msg);
146
+ return 0;
147
+ }
148
+ cur_msg = read_sha1_file(cur_sha1, &cur_type, &cur_len);
149
+ if (!cur_msg || !cur_len || cur_type != OBJ_BLOB) {
150
+ free(cur_msg);
151
+ free(new_msg);
152
+ hashcpy(cur_sha1, new_sha1);
153
+ return 0;
154
+ }
155
+
156
+ /* we will separate the notes by a newline anyway */
157
+ if (cur_msg[cur_len - 1] == '\n')
158
+ cur_len--;
159
+
160
+ /* concatenate cur_msg and new_msg into buf */
161
+ buf_len = cur_len + 1 + new_len;
162
+ buf = (char *) xmalloc(buf_len);
163
+ memcpy(buf, cur_msg, cur_len);
164
+ buf[cur_len] = '\n';
165
+ memcpy(buf + cur_len + 1, new_msg, new_len);
166
+
167
+ free(cur_msg);
168
+ free(new_msg);
169
+
170
+ /* create a new blob object from buf */
171
+ ret = write_sha1_file(buf, buf_len, "blob", cur_sha1);
172
+ free(buf);
173
+ return ret;
174
+}
175
+
176
/*
177
* To insert a leaf_node:
129
- * 1. Start at the root node, with n = 0
130
- * 2. Use the nth nibble of the key as an index into a:
131
- * - If a[n] is NULL, store the tweaked pointer directly into a[n]
132
- * - If a[n] is an int_node, recurse into that node and increment n
133
- * - If a[n] is a leaf_node:
134
- * 1. Check if they're equal, and handle that (abort? overwrite?)
135
- * 2. Create a new int_node, and store both leaf_nodes there
136
- * 3. Store the new int_node into a[n].
178
+ * Search to the tree location appropriate for the given leaf_node's key:
179
+ * - If location is unused (NULL), store the tweaked pointer directly there
180
+ * - If location holds a note entry that matches the note-to-be-inserted, then
181
+ * concatenate the two notes.
182
+ * - If location holds a note entry that matches the subtree-to-be-inserted,
183
+ * then unpack the subtree-to-be-inserted into the location.
184
+ * - If location holds a matching subtree entry, unpack the subtree at that
185
+ * location, and restart the insert operation from that level.
186
+ * - Else, create a new int_node, holding both the node-at-location and the
187
+ * node-to-be-inserted, and store the new int_node into the location.
188
*/
138
-static int note_tree_insert(struct int_node *tree, unsigned char n,
139
- const struct leaf_node *entry, unsigned char type)
189
+static void note_tree_insert(struct int_node *tree, unsigned char n,
190
+ struct leaf_node *entry, unsigned char type)
191
{
192
struct int_node *new_node;
142
- const struct leaf_node *l;
143
- int ret;
144
- unsigned char i = GET_NIBBLE(n, entry->key_sha1);
145
- void *p = tree->a[i];
146
- assert(GET_PTR_TYPE(entry) == PTR_TYPE_NULL);
147
- switch(GET_PTR_TYPE(p)) {
193
+ struct leaf_node *l;
194
+ void **p = note_tree_search(&tree, &n, entry->key_sha1);
195
+
196
+ assert(GET_PTR_TYPE(entry) == 0); /* no type bits set */
197
+ l = (struct leaf_node *) CLR_PTR_TYPE(*p);
198
+ switch(GET_PTR_TYPE(*p)) {
199
case PTR_TYPE_NULL:
149
- assert(!p);
150
- tree->a[i] = SET_PTR_TYPE(entry, type);
151
- return 0;
152
- case PTR_TYPE_INTERNAL:
153
- return note_tree_insert(CLR_PTR_TYPE(p), n + 1, entry, type);
154
- default:
155
- assert(GET_PTR_TYPE(p) == PTR_TYPE_NOTE ||
156
- GET_PTR_TYPE(p) == PTR_TYPE_SUBTREE);
157
- l = (const struct leaf_node *) CLR_PTR_TYPE(p);
158
- if (!hashcmp(entry->key_sha1, l->key_sha1))
159
- return -1; /* abort insert on matching key */
160
- new_node = (struct int_node *)
161
- xcalloc(sizeof(struct int_node), 1);
162
- ret = note_tree_insert(new_node, n + 1,
163
- CLR_PTR_TYPE(p), GET_PTR_TYPE(p));
164
- if (ret) {
165
- free(new_node);
166
- return -1;
200
+ assert(!*p);
201
+ *p = SET_PTR_TYPE(entry, type);
202
+ return;
203
+ case PTR_TYPE_NOTE:
204
+ switch (type) {
205
+ case PTR_TYPE_NOTE:
206
+ if (!hashcmp(l->key_sha1, entry->key_sha1)) {
207
+ /* skip concatenation if l == entry */
208
+ if (!hashcmp(l->val_sha1, entry->val_sha1))
209
+ return;
210
+
211
+ if (concatenate_notes(l->val_sha1,
212
+ entry->val_sha1))
213
+ die("failed to concatenate note %s "
214
+ "into note %s for commit %s",
215
+ sha1_to_hex(entry->val_sha1),
216
+ sha1_to_hex(l->val_sha1),
217
+ sha1_to_hex(l->key_sha1));
218
+ free(entry);
219
+ return;
220
+ }
221
+ break;
222
+ case PTR_TYPE_SUBTREE:
223
+ if (!SUBTREE_SHA1_PREFIXCMP(l->key_sha1,
224
+ entry->key_sha1)) {
225
+ /* unpack 'entry' */
226
+ load_subtree(entry, tree, n);
227
+ free(entry);
228
+ return;
229
+ }
230
+ break;
231
+ }
232
+ break;
233
+ case PTR_TYPE_SUBTREE:
234
+ if (!SUBTREE_SHA1_PREFIXCMP(entry->key_sha1, l->key_sha1)) {
235
+ /* unpack 'l' and restart insert */
236
+ *p = NULL;
237
+ load_subtree(l, tree, n);
238
+ free(l);
239
+ note_tree_insert(tree, n, entry, type);
240
+ return;
241
}
168
- tree->a[i] = SET_PTR_TYPE(new_node, PTR_TYPE_INTERNAL);
169
- return note_tree_insert(new_node, n + 1, entry, type);
242
+ break;
243
}
244
+
245
+ /* non-matching leaf_node */
246
+ assert(GET_PTR_TYPE(*p) == PTR_TYPE_NOTE ||
247
+ GET_PTR_TYPE(*p) == PTR_TYPE_SUBTREE);
248
+ new_node = (struct int_node *) xcalloc(sizeof(struct int_node), 1);
249
+ note_tree_insert(new_node, n + 1, l, GET_PTR_TYPE(*p));
250
+ *p = SET_PTR_TYPE(new_node, PTR_TYPE_INTERNAL);
251
+ note_tree_insert(new_node, n + 1, entry, type);
252
}
253
254
/* Free the entire notes data contained in the given tree */
301
{
302
unsigned char commit_sha1[20];
303
unsigned int prefix_len;
223
- int status;
304
void *buf;
305
struct tree_desc desc;
306
struct name_entry entry;
334
l->key_sha1[19] = (unsigned char) len;
335
type = PTR_TYPE_SUBTREE;
336
}
257
- status = note_tree_insert(node, n, l, type);
258
- assert(!status);
337
+ note_tree_insert(node, n, l, type);
338
}
339
}
340
free(buf);