45
#define CACHE_EXT_UNTRACKED 0x554E5452 /* "UNTR" */
46
#define CACHE_EXT_FSMONITOR 0x46534D4E /* "FSMN" */
47
#define CACHE_EXT_ENDOFINDEXENTRIES 0x454F4945 /* "EOIE" */
48
+#define CACHE_EXT_INDEXENTRYOFFSETTABLE 0x49454F54 /* "IEOT" */
49
50
/* changes that can be kept in $GIT_DIR/index (basically all extensions) */
51
#define EXTMASK (RESOLVE_UNDO_CHANGED | CACHE_TREE_CHANGED | \
1697
read_fsmonitor_extension(istate, data, sz);
1698
break;
1699
case CACHE_EXT_ENDOFINDEXENTRIES:
1700
+ case CACHE_EXT_INDEXENTRYOFFSETTABLE:
1701
/* already handled in do_read_index() */
1702
break;
1703
default:
1890
return ondisk_size + entries * per_entry;
1891
}
1892
1893
+struct index_entry_offset
1894
+{
1895
+ /* starting byte offset into index file, count of index entries in this block */
1896
+ int offset, nr;
1897
+};
1898
+
1899
+struct index_entry_offset_table
1900
+{
1901
+ int nr;
1902
+ struct index_entry_offset entries[FLEX_ARRAY];
1903
+};
1904
+
1905
+#ifndef NO_PTHREADS
1906
+static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset);
1907
+static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_table *ieot);
1908
+#endif
1909
+
1910
static size_t read_eoie_extension(const char *mmap, size_t mmap_size);
1911
static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context, size_t offset);
1912
1948
return NULL;
1949
}
1950
1951
+/*
1952
+ * Mostly randomly chosen maximum thread counts: we
1953
+ * cap the parallelism to online_cpus() threads, and we want
1954
+ * to have at least 10000 cache entries per thread for it to
1955
+ * be worth starting a thread.
1956
+ */
1957
+
1958
+#define THREAD_COST (10000)
1959
+
1960
/* remember to discard_cache() before reading a different cache! */
1961
int do_read_index(struct index_state *istate, const char *path, int must_exist)
1962
{
2549
struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
2550
int drop_cache_tree = istate->drop_cache_tree;
2551
off_t offset;
2552
+ int ieot_blocks = 1;
2553
+ struct index_entry_offset_table *ieot = NULL;
2554
+ int nr, nr_threads;
2555
2556
for (i = removed = extended = 0; i < entries; i++) {
2557
if (cache[i]->ce_flags & CE_REMOVE)
2585
if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
2586
return -1;
2587
2588
+#ifndef NO_PTHREADS
2589
+ nr_threads = git_config_get_index_threads();
2590
+ if (nr_threads != 1) {
2591
+ int ieot_blocks, cpus;
2592
+
2593
+ /*
2594
+ * ensure default number of ieot blocks maps evenly to the
2595
+ * default number of threads that will process them leaving
2596
+ * room for the thread to load the index extensions.
2597
+ */
2598
+ if (!nr_threads) {
2599
+ ieot_blocks = istate->cache_nr / THREAD_COST;
2600
+ cpus = online_cpus();
2601
+ if (ieot_blocks > cpus - 1)
2602
+ ieot_blocks = cpus - 1;
2603
+ } else {
2604
+ ieot_blocks = nr_threads;
2605
+ }
2606
+
2607
+ /*
2608
+ * no reason to write out the IEOT extension if we don't
2609
+ * have enough blocks to utilize multi-threading
2610
+ */
2611
+ if (ieot_blocks > 1) {
2612
+ ieot = xcalloc(1, sizeof(struct index_entry_offset_table)
2613
+ + (ieot_blocks * sizeof(struct index_entry_offset)));
2614
+ ieot_blocks = DIV_ROUND_UP(entries, ieot_blocks);
2615
+ }
2616
+ }
2617
+#endif
2618
+
2619
offset = lseek(newfd, 0, SEEK_CUR);
2558
- if (offset < 0)
2620
+ if (offset < 0) {
2621
+ free(ieot);
2622
return -1;
2623
+ }
2624
offset += write_buffer_len;
2625
+ nr = 0;
2626
previous_name = (hdr_version == 4) ? &previous_name_buf : NULL;
2627
2628
for (i = 0; i < entries; i++) {
2644
2645
drop_cache_tree = 1;
2646
}
2647
+ if (ieot && i && (i % ieot_blocks == 0)) {
2648
+ ieot->entries[ieot->nr].nr = nr;
2649
+ ieot->entries[ieot->nr].offset = offset;
2650
+ ieot->nr++;
2651
+ /*
2652
+ * If we have a V4 index, set the first byte to an invalid
2653
+ * character to ensure there is nothing common with the previous
2654
+ * entry
2655
+ */
2656
+ if (previous_name)
2657
+ previous_name->buf[0] = 0;
2658
+ nr = 0;
2659
+ offset = lseek(newfd, 0, SEEK_CUR);
2660
+ if (offset < 0) {
2661
+ free(ieot);
2662
+ return -1;
2663
+ }
2664
+ offset += write_buffer_len;
2665
+ }
2666
if (ce_write_entry(&c, newfd, ce, previous_name, (struct ondisk_cache_entry *)&ondisk) < 0)
2667
err = -1;
2668
2669
if (err)
2670
break;
2671
+ nr++;
2672
+ }
2673
+ if (ieot && nr) {
2674
+ ieot->entries[ieot->nr].nr = nr;
2675
+ ieot->entries[ieot->nr].offset = offset;
2676
+ ieot->nr++;
2677
}
2678
strbuf_release(&previous_name_buf);
2679
2590
- if (err)
2680
+ if (err) {
2681
+ free(ieot);
2682
return err;
2683
+ }
2684
2685
/* Write extension data here */
2686
offset = lseek(newfd, 0, SEEK_CUR);
2595
- if (offset < 0)
2687
+ if (offset < 0) {
2688
+ free(ieot);
2689
return -1;
2690
+ }
2691
offset += write_buffer_len;
2692
the_hash_algo->init_fn(&eoie_c);
2693
2694
+ /*
2695
+ * Lets write out CACHE_EXT_INDEXENTRYOFFSETTABLE first so that we
2696
+ * can minimize the number of extensions we have to scan through to
2697
+ * find it during load. Write it out regardless of the
2698
+ * strip_extensions parameter as we need it when loading the shared
2699
+ * index.
2700
+ */
2701
+#ifndef NO_PTHREADS
2702
+ if (ieot) {
2703
+ struct strbuf sb = STRBUF_INIT;
2704
+
2705
+ write_ieot_extension(&sb, ieot);
2706
+ err = write_index_ext_header(&c, &eoie_c, newfd, CACHE_EXT_INDEXENTRYOFFSETTABLE, sb.len) < 0
2707
+ || ce_write(&c, newfd, sb.buf, sb.len) < 0;
2708
+ strbuf_release(&sb);
2709
+ free(ieot);
2710
+ if (err)
2711
+ return -1;
2712
+ }
2713
+#endif
2714
+
2715
if (!strip_extensions && istate->split_index) {
2716
struct strbuf sb = STRBUF_INIT;
2717
3295
the_hash_algo->final_fn(hash, eoie_context);
3296
strbuf_add(sb, hash, the_hash_algo->rawsz);
3297
}
3298
+
3299
+#ifndef NO_PTHREADS
3300
+#define IEOT_VERSION (1)
3301
+
3302
+static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset)
3303
+{
3304
+ const char *index = NULL;
3305
+ uint32_t extsize, ext_version;
3306
+ struct index_entry_offset_table *ieot;
3307
+ int i, nr;
3308
+
3309
+ /* find the IEOT extension */
3310
+ if (!offset)
3311
+ return NULL;
3312
+ while (offset <= mmap_size - the_hash_algo->rawsz - 8) {
3313
+ extsize = get_be32(mmap + offset + 4);
3314
+ if (CACHE_EXT((mmap + offset)) == CACHE_EXT_INDEXENTRYOFFSETTABLE) {
3315
+ index = mmap + offset + 4 + 4;
3316
+ break;
3317
+ }
3318
+ offset += 8;
3319
+ offset += extsize;
3320
+ }
3321
+ if (!index)
3322
+ return NULL;
3323
+
3324
+ /* validate the version is IEOT_VERSION */
3325
+ ext_version = get_be32(index);
3326
+ if (ext_version != IEOT_VERSION) {
3327
+ error("invalid IEOT version %d", ext_version);
3328
+ return NULL;
3329
+ }
3330
+ index += sizeof(uint32_t);
3331
+
3332
+ /* extension size - version bytes / bytes per entry */
3333
+ nr = (extsize - sizeof(uint32_t)) / (sizeof(uint32_t) + sizeof(uint32_t));
3334
+ if (!nr) {
3335
+ error("invalid number of IEOT entries %d", nr);
3336
+ return NULL;
3337
+ }
3338
+ ieot = xmalloc(sizeof(struct index_entry_offset_table)
3339
+ + (nr * sizeof(struct index_entry_offset)));
3340
+ ieot->nr = nr;
3341
+ for (i = 0; i < nr; i++) {
3342
+ ieot->entries[i].offset = get_be32(index);
3343
+ index += sizeof(uint32_t);
3344
+ ieot->entries[i].nr = get_be32(index);
3345
+ index += sizeof(uint32_t);
3346
+ }
3347
+
3348
+ return ieot;
3349
+}
3350
+
3351
+static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_table *ieot)
3352
+{
3353
+ uint32_t buffer;
3354
+ int i;
3355
+
3356
+ /* version */
3357
+ put_be32(&buffer, IEOT_VERSION);
3358
+ strbuf_add(sb, &buffer, sizeof(uint32_t));
3359
+
3360
+ /* ieot */
3361
+ for (i = 0; i < ieot->nr; i++) {
3362
+
3363
+ /* offset */
3364
+ put_be32(&buffer, ieot->entries[i].offset);
3365
+ strbuf_add(sb, &buffer, sizeof(uint32_t));
3366
+
3367
+ /* count */
3368
+ put_be32(&buffer, ieot->entries[i].nr);
3369
+ strbuf_add(sb, &buffer, sizeof(uint32_t));
3370
+ }
3371
+}
3372
+#endif