9
#include "progress.h"
10
#include "fsck.h"
11
#include "exec_cmd.h"
12
+#include "thread-utils.h"
13
14
static const char index_pack_usage[] =
15
"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
39
int ofs_first, ofs_last;
40
};
41
42
+struct thread_local {
43
+#ifndef NO_PTHREADS
44
+ pthread_t thread;
45
+#endif
46
+ struct base_data *base_cache;
47
+ size_t base_cache_used;
48
+};
49
+
50
/*
51
* Even if sizeof(union delta_base) == 24 on 64-bit archs, we really want
52
* to memcmp() only the first 20 bytes.
63
64
static struct object_entry *objects;
65
static struct delta_entry *deltas;
57
-static struct base_data *base_cache;
58
-static size_t base_cache_used;
66
+static struct thread_local nothread_data;
67
static int nr_objects;
68
static int nr_deltas;
69
static int nr_resolved_deltas;
70
+static int nr_threads;
71
72
static int from_stdin;
73
static int strict;
84
static uint32_t input_crc32;
85
static int input_fd, output_fd, pack_fd;
86
87
+#ifndef NO_PTHREADS
88
+
89
+static struct thread_local *thread_data;
90
+static int nr_dispatched;
91
+static int threads_active;
92
+
93
+static pthread_mutex_t read_mutex;
94
+#define read_lock() lock_mutex(&read_mutex)
95
+#define read_unlock() unlock_mutex(&read_mutex)
96
+
97
+static pthread_mutex_t counter_mutex;
98
+#define counter_lock() lock_mutex(&counter_mutex)
99
+#define counter_unlock() unlock_mutex(&counter_mutex)
100
+
101
+static pthread_mutex_t work_mutex;
102
+#define work_lock() lock_mutex(&work_mutex)
103
+#define work_unlock() unlock_mutex(&work_mutex)
104
+
105
+static pthread_key_t key;
106
+
107
+static inline void lock_mutex(pthread_mutex_t *mutex)
108
+{
109
+ if (threads_active)
110
+ pthread_mutex_lock(mutex);
111
+}
112
+
113
+static inline void unlock_mutex(pthread_mutex_t *mutex)
114
+{
115
+ if (threads_active)
116
+ pthread_mutex_unlock(mutex);
117
+}
118
+
119
+/*
120
+ * Mutex and conditional variable can't be statically-initialized on Windows.
121
+ */
122
+static void init_thread(void)
123
+{
124
+ init_recursive_mutex(&read_mutex);
125
+ pthread_mutex_init(&counter_mutex, NULL);
126
+ pthread_mutex_init(&work_mutex, NULL);
127
+ pthread_key_create(&key, NULL);
128
+ thread_data = xcalloc(nr_threads, sizeof(*thread_data));
129
+ threads_active = 1;
130
+}
131
+
132
+static void cleanup_thread(void)
133
+{
134
+ if (!threads_active)
135
+ return;
136
+ threads_active = 0;
137
+ pthread_mutex_destroy(&read_mutex);
138
+ pthread_mutex_destroy(&counter_mutex);
139
+ pthread_mutex_destroy(&work_mutex);
140
+ pthread_key_delete(key);
141
+ free(thread_data);
142
+}
143
+
144
+#else
145
+
146
+#define read_lock()
147
+#define read_unlock()
148
+
149
+#define counter_lock()
150
+#define counter_unlock()
151
+
152
+#define work_lock()
153
+#define work_unlock()
154
+
155
+#endif
156
+
157
+
158
static int mark_link(struct object *obj, int type, void *data)
159
{
160
if (!obj)
303
die("pack has bad object at offset %lu: %s", offset, buf);
304
}
305
306
+static inline struct thread_local *get_thread_data(void)
307
+{
308
+#ifndef NO_PTHREADS
309
+ if (threads_active)
310
+ return pthread_getspecific(key);
311
+ assert(!threads_active &&
312
+ "This should only be reached when all threads are gone");
313
+#endif
314
+ return ¬hread_data;
315
+}
316
+
317
+#ifndef NO_PTHREADS
318
+static void set_thread_data(struct thread_local *data)
319
+{
320
+ if (threads_active)
321
+ pthread_setspecific(key, data);
322
+}
323
+#endif
324
+
325
static struct base_data *alloc_base_data(void)
326
{
327
struct base_data *base = xmalloc(sizeof(struct base_data));
336
if (c->data) {
337
free(c->data);
338
c->data = NULL;
240
- base_cache_used -= c->size;
339
+ get_thread_data()->base_cache_used -= c->size;
340
}
341
}
342
343
static void prune_base_data(struct base_data *retain)
344
{
345
struct base_data *b;
247
- for (b = base_cache;
248
- base_cache_used > delta_base_cache_limit && b;
346
+ struct thread_local *data = get_thread_data();
347
+ for (b = data->base_cache;
348
+ data->base_cache_used > delta_base_cache_limit && b;
349
b = b->child) {
350
if (b->data && b != retain)
351
free_base_data(b);
357
if (base)
358
base->child = c;
359
else
260
- base_cache = c;
360
+ get_thread_data()->base_cache = c;
361
362
c->base = base;
363
c->child = NULL;
364
if (c->data)
265
- base_cache_used += c->size;
365
+ get_thread_data()->base_cache_used += c->size;
366
prune_base_data(c);
367
}
368
372
if (base)
373
base->child = NULL;
374
else
275
- base_cache = NULL;
375
+ get_thread_data()->base_cache = NULL;
376
free_base_data(c);
377
}
378
561
enum object_type type, unsigned char *sha1)
562
{
563
hash_sha1_file(data, size, typename(type), sha1);
564
+ read_lock();
565
if (has_sha1_file(sha1)) {
566
void *has_data;
567
enum object_type has_type;
568
unsigned long has_size;
569
has_data = read_sha1_file(sha1, &has_type, &has_size);
570
+ read_unlock();
571
if (!has_data)
572
die("cannot read existing object %s", sha1_to_hex(sha1));
573
if (size != has_size || type != has_type ||
574
memcmp(data, has_data, size) != 0)
575
die("SHA1 COLLISION FOUND WITH %s !", sha1_to_hex(sha1));
576
free(has_data);
475
- }
577
+ } else
578
+ read_unlock();
579
+
580
if (strict) {
581
+ read_lock();
582
if (type == OBJ_BLOB) {
583
struct blob *blob = lookup_blob(sha1);
584
if (blob)
612
}
613
obj->flags |= FLAG_CHECKED;
614
}
615
+ read_unlock();
616
}
617
}
618
658
if (!delta_nr) {
659
c->data = get_data_from_pack(obj);
660
c->size = obj->size;
555
- base_cache_used += c->size;
661
+ get_thread_data()->base_cache_used += c->size;
662
prune_base_data(c);
663
}
664
for (; delta_nr > 0; delta_nr--) {
674
free(raw);
675
if (!c->data)
676
bad_object(obj->idx.offset, "failed to apply delta");
571
- base_cache_used += c->size;
677
+ get_thread_data()->base_cache_used += c->size;
678
prune_base_data(c);
679
}
680
free(delta);
702
bad_object(delta_obj->idx.offset, "failed to apply delta");
703
sha1_object(result->data, result->size, delta_obj->real_type,
704
delta_obj->idx.sha1);
705
+ counter_lock();
706
nr_resolved_deltas++;
707
+ counter_unlock();
708
}
709
710
static struct base_data *find_unresolved_deltas_1(struct base_data *base,
798
find_unresolved_deltas(base_obj);
799
}
800
801
+#ifndef NO_PTHREADS
802
+static void *threaded_second_pass(void *data)
803
+{
804
+ set_thread_data(data);
805
+ for (;;) {
806
+ int i;
807
+ work_lock();
808
+ display_progress(progress, nr_resolved_deltas);
809
+ while (nr_dispatched < nr_objects &&
810
+ is_delta_type(objects[nr_dispatched].type))
811
+ nr_dispatched++;
812
+ if (nr_dispatched >= nr_objects) {
813
+ work_unlock();
814
+ break;
815
+ }
816
+ i = nr_dispatched++;
817
+ work_unlock();
818
+
819
+ resolve_base(&objects[i]);
820
+ }
821
+ return NULL;
822
+}
823
+#endif
824
+
825
/*
826
* First pass:
827
* - find locations of all objects;
890
891
if (verbose)
892
progress = start_progress("Resolving deltas", nr_deltas);
893
+
894
+#ifndef NO_PTHREADS
895
+ nr_dispatched = 0;
896
+ if (nr_threads > 1 || getenv("GIT_FORCE_THREADS")) {
897
+ init_thread();
898
+ for (i = 0; i < nr_threads; i++) {
899
+ int ret = pthread_create(&thread_data[i].thread, NULL,
900
+ threaded_second_pass, thread_data + i);
901
+ if (ret)
902
+ die("unable to create thread: %s", strerror(ret));
903
+ }
904
+ for (i = 0; i < nr_threads; i++)
905
+ pthread_join(thread_data[i].thread, NULL);
906
+ cleanup_thread();
907
+ return;
908
+ }
909
+#endif
910
+
911
for (i = 0; i < nr_objects; i++) {
912
struct object_entry *obj = &objects[i];
913
1166
die("bad pack.indexversion=%"PRIu32, opts->version);
1167
return 0;
1168
}
1169
+ if (!strcmp(k, "pack.threads")) {
1170
+ nr_threads = git_config_int(k, v);
1171
+ if (nr_threads < 0)
1172
+ die("invalid number of threads specified (%d)",
1173
+ nr_threads);
1174
+#ifdef NO_PTHREADS
1175
+ if (nr_threads != 1)
1176
+ warning("no threads support, ignoring %s", k);
1177
+ nr_threads = 1;
1178
+#endif
1179
+ return 0;
1180
+ }
1181
return git_default_config(k, v, cb);
1182
}
1183
1336
keep_msg = "";
1337
} else if (!prefixcmp(arg, "--keep=")) {
1338
keep_msg = arg + 7;
1339
+ } else if (!prefixcmp(arg, "--threads=")) {
1340
+ char *end;
1341
+ nr_threads = strtoul(arg+10, &end, 0);
1342
+ if (!arg[10] || *end || nr_threads < 0)
1343
+ usage(index_pack_usage);
1344
+#ifdef NO_PTHREADS
1345
+ if (nr_threads != 1)
1346
+ warning("no threads support, "
1347
+ "ignoring %s", arg);
1348
+ nr_threads = 1;
1349
+#endif
1350
} else if (!prefixcmp(arg, "--pack_header=")) {
1351
struct pack_header *hdr;
1352
char *c;
1418
if (strict)
1419
opts.flags |= WRITE_IDX_STRICT;
1420
1421
+#ifndef NO_PTHREADS
1422
+ if (!nr_threads) {
1423
+ nr_threads = online_cpus();
1424
+ /* An experiment showed that more threads does not mean faster */
1425
+ if (nr_threads > 3)
1426
+ nr_threads = 3;
1427
+ }
1428
+#endif
1429
+
1430
curr_pack = open_pack_file(pack_name);
1431
parse_pack_header();
1432
objects = xcalloc(nr_objects + 1, sizeof(struct object_entry));