1
#include "git-compat-util.h"
2
#include "bloom.h"
3
+#include "diff.h"
4
+#include "diffcore.h"
5
+#include "revision.h"
6
+#include "hashmap.h"
7
+
8
+define_commit_slab(bloom_filter_slab, struct bloom_filter);
9
+
10
+struct bloom_filter_slab bloom_filters;
11
+
12
+struct pathmap_hash_entry {
13
+ struct hashmap_entry entry;
14
+ const char path[FLEX_ARRAY];
15
+};
16
17
static uint32_t rotate_left(uint32_t value, int32_t count)
18
{
120
filter->data[block_pos] |= get_bitmask(hash_mod);
121
}
122
}
123
+
124
+void init_bloom_filters(void)
125
+{
126
+ init_bloom_filter_slab(&bloom_filters);
127
+}
128
+
129
+struct bloom_filter *get_bloom_filter(struct repository *r,
130
+ struct commit *c)
131
+{
132
+ struct bloom_filter *filter;
133
+ struct bloom_filter_settings settings = DEFAULT_BLOOM_FILTER_SETTINGS;
134
+ int i;
135
+ struct diff_options diffopt;
136
+
137
+ if (bloom_filters.slab_size == 0)
138
+ return NULL;
139
+
140
+ filter = bloom_filter_slab_at(&bloom_filters, c);
141
+
142
+ repo_diff_setup(r, &diffopt);
143
+ diffopt.flags.recursive = 1;
144
+ diff_setup_done(&diffopt);
145
+
146
+ if (c->parents)
147
+ diff_tree_oid(&c->parents->item->object.oid, &c->object.oid, "", &diffopt);
148
+ else
149
+ diff_tree_oid(NULL, &c->object.oid, "", &diffopt);
150
+ diffcore_std(&diffopt);
151
+
152
+ if (diff_queued_diff.nr <= 512) {
153
+ struct hashmap pathmap;
154
+ struct pathmap_hash_entry *e;
155
+ struct hashmap_iter iter;
156
+ hashmap_init(&pathmap, NULL, NULL, 0);
157
+
158
+ for (i = 0; i < diff_queued_diff.nr; i++) {
159
+ const char *path = diff_queued_diff.queue[i]->two->path;
160
+
161
+ /*
162
+ * Add each leading directory of the changed file, i.e. for
163
+ * 'dir/subdir/file' add 'dir' and 'dir/subdir' as well, so
164
+ * the Bloom filter could be used to speed up commands like
165
+ * 'git log dir/subdir', too.
166
+ *
167
+ * Note that directories are added without the trailing '/'.
168
+ */
169
+ do {
170
+ char *last_slash = strrchr(path, '/');
171
+
172
+ FLEX_ALLOC_STR(e, path, path);
173
+ hashmap_entry_init(&e->entry, strhash(path));
174
+ hashmap_add(&pathmap, &e->entry);
175
+
176
+ if (!last_slash)
177
+ last_slash = (char*)path;
178
+ *last_slash = '\0';
179
+
180
+ } while (*path);
181
+
182
+ diff_free_filepair(diff_queued_diff.queue[i]);
183
+ }
184
+
185
+ filter->len = (hashmap_get_size(&pathmap) * settings.bits_per_entry + BITS_PER_WORD - 1) / BITS_PER_WORD;
186
+ filter->data = xcalloc(filter->len, sizeof(unsigned char));
187
+
188
+ hashmap_for_each_entry(&pathmap, &iter, e, entry) {
189
+ struct bloom_key key;
190
+ fill_bloom_key(e->path, strlen(e->path), &key, &settings);
191
+ add_key_to_filter(&key, filter, &settings);
192
+ }
193
+
194
+ hashmap_free_entries(&pathmap, struct pathmap_hash_entry, entry);
195
+ } else {
196
+ for (i = 0; i < diff_queued_diff.nr; i++)
197
+ diff_free_filepair(diff_queued_diff.queue[i]);
198
+ filter->data = NULL;
199
+ filter->len = 0;
200
+ }
201
+
202
+ free(diff_queued_diff.queue);
203
+ DIFF_QUEUE_CLEAR(&diff_queued_diff);
204
+
205
+ return filter;
206
+}