]> git.ipfire.org Git - thirdparty/git.git/blob - reftable/stack.c
Merge branch 'sp/test-i18ngrep' into maint-2.43
[thirdparty/git.git] / reftable / stack.c
1 /*
2 Copyright 2020 Google LLC
3
4 Use of this source code is governed by a BSD-style
5 license that can be found in the LICENSE file or at
6 https://developers.google.com/open-source/licenses/bsd
7 */
8
9 #include "stack.h"
10
11 #include "system.h"
12 #include "merged.h"
13 #include "reader.h"
14 #include "refname.h"
15 #include "reftable-error.h"
16 #include "reftable-record.h"
17 #include "reftable-merged.h"
18 #include "writer.h"
19
20 #include "tempfile.h"
21
22 static int stack_try_add(struct reftable_stack *st,
23 int (*write_table)(struct reftable_writer *wr,
24 void *arg),
25 void *arg);
26 static int stack_write_compact(struct reftable_stack *st,
27 struct reftable_writer *wr, int first, int last,
28 struct reftable_log_expiry_config *config);
29 static int stack_check_addition(struct reftable_stack *st,
30 const char *new_tab_name);
31 static void reftable_addition_close(struct reftable_addition *add);
32 static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st,
33 int reuse_open);
34
35 static void stack_filename(struct strbuf *dest, struct reftable_stack *st,
36 const char *name)
37 {
38 strbuf_reset(dest);
39 strbuf_addstr(dest, st->reftable_dir);
40 strbuf_addstr(dest, "/");
41 strbuf_addstr(dest, name);
42 }
43
44 static ssize_t reftable_fd_write(void *arg, const void *data, size_t sz)
45 {
46 int *fdp = (int *)arg;
47 return write_in_full(*fdp, data, sz);
48 }
49
50 int reftable_new_stack(struct reftable_stack **dest, const char *dir,
51 struct reftable_write_options config)
52 {
53 struct reftable_stack *p =
54 reftable_calloc(sizeof(struct reftable_stack));
55 struct strbuf list_file_name = STRBUF_INIT;
56 int err = 0;
57
58 if (config.hash_id == 0) {
59 config.hash_id = GIT_SHA1_FORMAT_ID;
60 }
61
62 *dest = NULL;
63
64 strbuf_reset(&list_file_name);
65 strbuf_addstr(&list_file_name, dir);
66 strbuf_addstr(&list_file_name, "/tables.list");
67
68 p->list_file = strbuf_detach(&list_file_name, NULL);
69 p->reftable_dir = xstrdup(dir);
70 p->config = config;
71
72 err = reftable_stack_reload_maybe_reuse(p, 1);
73 if (err < 0) {
74 reftable_stack_destroy(p);
75 } else {
76 *dest = p;
77 }
78 return err;
79 }
80
81 static int fd_read_lines(int fd, char ***namesp)
82 {
83 off_t size = lseek(fd, 0, SEEK_END);
84 char *buf = NULL;
85 int err = 0;
86 if (size < 0) {
87 err = REFTABLE_IO_ERROR;
88 goto done;
89 }
90 err = lseek(fd, 0, SEEK_SET);
91 if (err < 0) {
92 err = REFTABLE_IO_ERROR;
93 goto done;
94 }
95
96 buf = reftable_malloc(size + 1);
97 if (read_in_full(fd, buf, size) != size) {
98 err = REFTABLE_IO_ERROR;
99 goto done;
100 }
101 buf[size] = 0;
102
103 parse_names(buf, size, namesp);
104
105 done:
106 reftable_free(buf);
107 return err;
108 }
109
110 int read_lines(const char *filename, char ***namesp)
111 {
112 int fd = open(filename, O_RDONLY);
113 int err = 0;
114 if (fd < 0) {
115 if (errno == ENOENT) {
116 *namesp = reftable_calloc(sizeof(char *));
117 return 0;
118 }
119
120 return REFTABLE_IO_ERROR;
121 }
122 err = fd_read_lines(fd, namesp);
123 close(fd);
124 return err;
125 }
126
127 struct reftable_merged_table *
128 reftable_stack_merged_table(struct reftable_stack *st)
129 {
130 return st->merged;
131 }
132
133 static int has_name(char **names, const char *name)
134 {
135 while (*names) {
136 if (!strcmp(*names, name))
137 return 1;
138 names++;
139 }
140 return 0;
141 }
142
143 /* Close and free the stack */
144 void reftable_stack_destroy(struct reftable_stack *st)
145 {
146 char **names = NULL;
147 int err = 0;
148 if (st->merged) {
149 reftable_merged_table_free(st->merged);
150 st->merged = NULL;
151 }
152
153 err = read_lines(st->list_file, &names);
154 if (err < 0) {
155 FREE_AND_NULL(names);
156 }
157
158 if (st->readers) {
159 int i = 0;
160 struct strbuf filename = STRBUF_INIT;
161 for (i = 0; i < st->readers_len; i++) {
162 const char *name = reader_name(st->readers[i]);
163 strbuf_reset(&filename);
164 if (names && !has_name(names, name)) {
165 stack_filename(&filename, st, name);
166 }
167 reftable_reader_free(st->readers[i]);
168
169 if (filename.len) {
170 /* On Windows, can only unlink after closing. */
171 unlink(filename.buf);
172 }
173 }
174 strbuf_release(&filename);
175 st->readers_len = 0;
176 FREE_AND_NULL(st->readers);
177 }
178 FREE_AND_NULL(st->list_file);
179 FREE_AND_NULL(st->reftable_dir);
180 reftable_free(st);
181 free_names(names);
182 }
183
184 static struct reftable_reader **stack_copy_readers(struct reftable_stack *st,
185 int cur_len)
186 {
187 struct reftable_reader **cur =
188 reftable_calloc(sizeof(struct reftable_reader *) * cur_len);
189 int i = 0;
190 for (i = 0; i < cur_len; i++) {
191 cur[i] = st->readers[i];
192 }
193 return cur;
194 }
195
196 static int reftable_stack_reload_once(struct reftable_stack *st, char **names,
197 int reuse_open)
198 {
199 int cur_len = !st->merged ? 0 : st->merged->stack_len;
200 struct reftable_reader **cur = stack_copy_readers(st, cur_len);
201 int err = 0;
202 int names_len = names_length(names);
203 struct reftable_reader **new_readers =
204 reftable_calloc(sizeof(struct reftable_reader *) * names_len);
205 struct reftable_table *new_tables =
206 reftable_calloc(sizeof(struct reftable_table) * names_len);
207 int new_readers_len = 0;
208 struct reftable_merged_table *new_merged = NULL;
209 struct strbuf table_path = STRBUF_INIT;
210 int i;
211
212 while (*names) {
213 struct reftable_reader *rd = NULL;
214 char *name = *names++;
215
216 /* this is linear; we assume compaction keeps the number of
217 tables under control so this is not quadratic. */
218 int j = 0;
219 for (j = 0; reuse_open && j < cur_len; j++) {
220 if (cur[j] && 0 == strcmp(cur[j]->name, name)) {
221 rd = cur[j];
222 cur[j] = NULL;
223 break;
224 }
225 }
226
227 if (!rd) {
228 struct reftable_block_source src = { NULL };
229 stack_filename(&table_path, st, name);
230
231 err = reftable_block_source_from_file(&src,
232 table_path.buf);
233 if (err < 0)
234 goto done;
235
236 err = reftable_new_reader(&rd, &src, name);
237 if (err < 0)
238 goto done;
239 }
240
241 new_readers[new_readers_len] = rd;
242 reftable_table_from_reader(&new_tables[new_readers_len], rd);
243 new_readers_len++;
244 }
245
246 /* success! */
247 err = reftable_new_merged_table(&new_merged, new_tables,
248 new_readers_len, st->config.hash_id);
249 if (err < 0)
250 goto done;
251
252 new_tables = NULL;
253 st->readers_len = new_readers_len;
254 if (st->merged) {
255 merged_table_release(st->merged);
256 reftable_merged_table_free(st->merged);
257 }
258 if (st->readers) {
259 reftable_free(st->readers);
260 }
261 st->readers = new_readers;
262 new_readers = NULL;
263 new_readers_len = 0;
264
265 new_merged->suppress_deletions = 1;
266 st->merged = new_merged;
267 for (i = 0; i < cur_len; i++) {
268 if (cur[i]) {
269 const char *name = reader_name(cur[i]);
270 stack_filename(&table_path, st, name);
271
272 reader_close(cur[i]);
273 reftable_reader_free(cur[i]);
274
275 /* On Windows, can only unlink after closing. */
276 unlink(table_path.buf);
277 }
278 }
279
280 done:
281 for (i = 0; i < new_readers_len; i++) {
282 reader_close(new_readers[i]);
283 reftable_reader_free(new_readers[i]);
284 }
285 reftable_free(new_readers);
286 reftable_free(new_tables);
287 reftable_free(cur);
288 strbuf_release(&table_path);
289 return err;
290 }
291
292 /* return negative if a before b. */
293 static int tv_cmp(struct timeval *a, struct timeval *b)
294 {
295 time_t diff = a->tv_sec - b->tv_sec;
296 int udiff = a->tv_usec - b->tv_usec;
297
298 if (diff != 0)
299 return diff;
300
301 return udiff;
302 }
303
304 static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st,
305 int reuse_open)
306 {
307 struct timeval deadline = { 0 };
308 int err = gettimeofday(&deadline, NULL);
309 int64_t delay = 0;
310 int tries = 0;
311 if (err < 0)
312 return err;
313
314 deadline.tv_sec += 3;
315 while (1) {
316 char **names = NULL;
317 char **names_after = NULL;
318 struct timeval now = { 0 };
319 int err = gettimeofday(&now, NULL);
320 int err2 = 0;
321 if (err < 0) {
322 return err;
323 }
324
325 /* Only look at deadlines after the first few times. This
326 simplifies debugging in GDB */
327 tries++;
328 if (tries > 3 && tv_cmp(&now, &deadline) >= 0) {
329 break;
330 }
331
332 err = read_lines(st->list_file, &names);
333 if (err < 0) {
334 free_names(names);
335 return err;
336 }
337 err = reftable_stack_reload_once(st, names, reuse_open);
338 if (err == 0) {
339 free_names(names);
340 break;
341 }
342 if (err != REFTABLE_NOT_EXIST_ERROR) {
343 free_names(names);
344 return err;
345 }
346
347 /* err == REFTABLE_NOT_EXIST_ERROR can be caused by a concurrent
348 writer. Check if there was one by checking if the name list
349 changed.
350 */
351 err2 = read_lines(st->list_file, &names_after);
352 if (err2 < 0) {
353 free_names(names);
354 return err2;
355 }
356
357 if (names_equal(names_after, names)) {
358 free_names(names);
359 free_names(names_after);
360 return err;
361 }
362 free_names(names);
363 free_names(names_after);
364
365 delay = delay + (delay * rand()) / RAND_MAX + 1;
366 sleep_millisec(delay);
367 }
368
369 return 0;
370 }
371
372 /* -1 = error
373 0 = up to date
374 1 = changed. */
375 static int stack_uptodate(struct reftable_stack *st)
376 {
377 char **names = NULL;
378 int err = read_lines(st->list_file, &names);
379 int i = 0;
380 if (err < 0)
381 return err;
382
383 for (i = 0; i < st->readers_len; i++) {
384 if (!names[i]) {
385 err = 1;
386 goto done;
387 }
388
389 if (strcmp(st->readers[i]->name, names[i])) {
390 err = 1;
391 goto done;
392 }
393 }
394
395 if (names[st->merged->stack_len]) {
396 err = 1;
397 goto done;
398 }
399
400 done:
401 free_names(names);
402 return err;
403 }
404
405 int reftable_stack_reload(struct reftable_stack *st)
406 {
407 int err = stack_uptodate(st);
408 if (err > 0)
409 return reftable_stack_reload_maybe_reuse(st, 1);
410 return err;
411 }
412
413 int reftable_stack_add(struct reftable_stack *st,
414 int (*write)(struct reftable_writer *wr, void *arg),
415 void *arg)
416 {
417 int err = stack_try_add(st, write, arg);
418 if (err < 0) {
419 if (err == REFTABLE_LOCK_ERROR) {
420 /* Ignore error return, we want to propagate
421 REFTABLE_LOCK_ERROR.
422 */
423 reftable_stack_reload(st);
424 }
425 return err;
426 }
427
428 if (!st->disable_auto_compact)
429 return reftable_stack_auto_compact(st);
430
431 return 0;
432 }
433
434 static void format_name(struct strbuf *dest, uint64_t min, uint64_t max)
435 {
436 char buf[100];
437 uint32_t rnd = (uint32_t)git_rand();
438 snprintf(buf, sizeof(buf), "0x%012" PRIx64 "-0x%012" PRIx64 "-%08x",
439 min, max, rnd);
440 strbuf_reset(dest);
441 strbuf_addstr(dest, buf);
442 }
443
444 struct reftable_addition {
445 struct tempfile *lock_file;
446 struct reftable_stack *stack;
447
448 char **new_tables;
449 int new_tables_len;
450 uint64_t next_update_index;
451 };
452
453 #define REFTABLE_ADDITION_INIT {0}
454
455 static int reftable_stack_init_addition(struct reftable_addition *add,
456 struct reftable_stack *st)
457 {
458 struct strbuf lock_file_name = STRBUF_INIT;
459 int err = 0;
460 add->stack = st;
461
462 strbuf_addf(&lock_file_name, "%s.lock", st->list_file);
463
464 add->lock_file = create_tempfile(lock_file_name.buf);
465 if (!add->lock_file) {
466 if (errno == EEXIST) {
467 err = REFTABLE_LOCK_ERROR;
468 } else {
469 err = REFTABLE_IO_ERROR;
470 }
471 goto done;
472 }
473 if (st->config.default_permissions) {
474 if (chmod(add->lock_file->filename.buf, st->config.default_permissions) < 0) {
475 err = REFTABLE_IO_ERROR;
476 goto done;
477 }
478 }
479
480 err = stack_uptodate(st);
481 if (err < 0)
482 goto done;
483
484 if (err > 1) {
485 err = REFTABLE_LOCK_ERROR;
486 goto done;
487 }
488
489 add->next_update_index = reftable_stack_next_update_index(st);
490 done:
491 if (err) {
492 reftable_addition_close(add);
493 }
494 strbuf_release(&lock_file_name);
495 return err;
496 }
497
498 static void reftable_addition_close(struct reftable_addition *add)
499 {
500 int i = 0;
501 struct strbuf nm = STRBUF_INIT;
502 for (i = 0; i < add->new_tables_len; i++) {
503 stack_filename(&nm, add->stack, add->new_tables[i]);
504 unlink(nm.buf);
505 reftable_free(add->new_tables[i]);
506 add->new_tables[i] = NULL;
507 }
508 reftable_free(add->new_tables);
509 add->new_tables = NULL;
510 add->new_tables_len = 0;
511
512 delete_tempfile(&add->lock_file);
513 strbuf_release(&nm);
514 }
515
516 void reftable_addition_destroy(struct reftable_addition *add)
517 {
518 if (!add) {
519 return;
520 }
521 reftable_addition_close(add);
522 reftable_free(add);
523 }
524
525 int reftable_addition_commit(struct reftable_addition *add)
526 {
527 struct strbuf table_list = STRBUF_INIT;
528 int lock_file_fd = get_tempfile_fd(add->lock_file);
529 int i = 0;
530 int err = 0;
531
532 if (add->new_tables_len == 0)
533 goto done;
534
535 for (i = 0; i < add->stack->merged->stack_len; i++) {
536 strbuf_addstr(&table_list, add->stack->readers[i]->name);
537 strbuf_addstr(&table_list, "\n");
538 }
539 for (i = 0; i < add->new_tables_len; i++) {
540 strbuf_addstr(&table_list, add->new_tables[i]);
541 strbuf_addstr(&table_list, "\n");
542 }
543
544 err = write_in_full(lock_file_fd, table_list.buf, table_list.len);
545 strbuf_release(&table_list);
546 if (err < 0) {
547 err = REFTABLE_IO_ERROR;
548 goto done;
549 }
550
551 err = rename_tempfile(&add->lock_file, add->stack->list_file);
552 if (err < 0) {
553 err = REFTABLE_IO_ERROR;
554 goto done;
555 }
556
557 /* success, no more state to clean up. */
558 for (i = 0; i < add->new_tables_len; i++) {
559 reftable_free(add->new_tables[i]);
560 }
561 reftable_free(add->new_tables);
562 add->new_tables = NULL;
563 add->new_tables_len = 0;
564
565 err = reftable_stack_reload(add->stack);
566 if (err)
567 goto done;
568
569 if (!add->stack->disable_auto_compact)
570 err = reftable_stack_auto_compact(add->stack);
571
572 done:
573 reftable_addition_close(add);
574 return err;
575 }
576
577 int reftable_stack_new_addition(struct reftable_addition **dest,
578 struct reftable_stack *st)
579 {
580 int err = 0;
581 struct reftable_addition empty = REFTABLE_ADDITION_INIT;
582 *dest = reftable_calloc(sizeof(**dest));
583 **dest = empty;
584 err = reftable_stack_init_addition(*dest, st);
585 if (err) {
586 reftable_free(*dest);
587 *dest = NULL;
588 }
589 return err;
590 }
591
592 static int stack_try_add(struct reftable_stack *st,
593 int (*write_table)(struct reftable_writer *wr,
594 void *arg),
595 void *arg)
596 {
597 struct reftable_addition add = REFTABLE_ADDITION_INIT;
598 int err = reftable_stack_init_addition(&add, st);
599 if (err < 0)
600 goto done;
601 if (err > 0) {
602 err = REFTABLE_LOCK_ERROR;
603 goto done;
604 }
605
606 err = reftable_addition_add(&add, write_table, arg);
607 if (err < 0)
608 goto done;
609
610 err = reftable_addition_commit(&add);
611 done:
612 reftable_addition_close(&add);
613 return err;
614 }
615
616 int reftable_addition_add(struct reftable_addition *add,
617 int (*write_table)(struct reftable_writer *wr,
618 void *arg),
619 void *arg)
620 {
621 struct strbuf temp_tab_file_name = STRBUF_INIT;
622 struct strbuf tab_file_name = STRBUF_INIT;
623 struct strbuf next_name = STRBUF_INIT;
624 struct reftable_writer *wr = NULL;
625 int err = 0;
626 int tab_fd = 0;
627
628 strbuf_reset(&next_name);
629 format_name(&next_name, add->next_update_index, add->next_update_index);
630
631 stack_filename(&temp_tab_file_name, add->stack, next_name.buf);
632 strbuf_addstr(&temp_tab_file_name, ".temp.XXXXXX");
633
634 tab_fd = mkstemp(temp_tab_file_name.buf);
635 if (tab_fd < 0) {
636 err = REFTABLE_IO_ERROR;
637 goto done;
638 }
639 if (add->stack->config.default_permissions) {
640 if (chmod(temp_tab_file_name.buf, add->stack->config.default_permissions)) {
641 err = REFTABLE_IO_ERROR;
642 goto done;
643 }
644 }
645 wr = reftable_new_writer(reftable_fd_write, &tab_fd,
646 &add->stack->config);
647 err = write_table(wr, arg);
648 if (err < 0)
649 goto done;
650
651 err = reftable_writer_close(wr);
652 if (err == REFTABLE_EMPTY_TABLE_ERROR) {
653 err = 0;
654 goto done;
655 }
656 if (err < 0)
657 goto done;
658
659 err = close(tab_fd);
660 tab_fd = 0;
661 if (err < 0) {
662 err = REFTABLE_IO_ERROR;
663 goto done;
664 }
665
666 err = stack_check_addition(add->stack, temp_tab_file_name.buf);
667 if (err < 0)
668 goto done;
669
670 if (wr->min_update_index < add->next_update_index) {
671 err = REFTABLE_API_ERROR;
672 goto done;
673 }
674
675 format_name(&next_name, wr->min_update_index, wr->max_update_index);
676 strbuf_addstr(&next_name, ".ref");
677
678 stack_filename(&tab_file_name, add->stack, next_name.buf);
679
680 /*
681 On windows, this relies on rand() picking a unique destination name.
682 Maybe we should do retry loop as well?
683 */
684 err = rename(temp_tab_file_name.buf, tab_file_name.buf);
685 if (err < 0) {
686 err = REFTABLE_IO_ERROR;
687 goto done;
688 }
689
690 add->new_tables = reftable_realloc(add->new_tables,
691 sizeof(*add->new_tables) *
692 (add->new_tables_len + 1));
693 add->new_tables[add->new_tables_len] = strbuf_detach(&next_name, NULL);
694 add->new_tables_len++;
695 done:
696 if (tab_fd > 0) {
697 close(tab_fd);
698 tab_fd = 0;
699 }
700 if (temp_tab_file_name.len > 0) {
701 unlink(temp_tab_file_name.buf);
702 }
703
704 strbuf_release(&temp_tab_file_name);
705 strbuf_release(&tab_file_name);
706 strbuf_release(&next_name);
707 reftable_writer_free(wr);
708 return err;
709 }
710
711 uint64_t reftable_stack_next_update_index(struct reftable_stack *st)
712 {
713 int sz = st->merged->stack_len;
714 if (sz > 0)
715 return reftable_reader_max_update_index(st->readers[sz - 1]) +
716 1;
717 return 1;
718 }
719
720 static int stack_compact_locked(struct reftable_stack *st, int first, int last,
721 struct strbuf *temp_tab,
722 struct reftable_log_expiry_config *config)
723 {
724 struct strbuf next_name = STRBUF_INIT;
725 int tab_fd = -1;
726 struct reftable_writer *wr = NULL;
727 int err = 0;
728
729 format_name(&next_name,
730 reftable_reader_min_update_index(st->readers[first]),
731 reftable_reader_max_update_index(st->readers[last]));
732
733 stack_filename(temp_tab, st, next_name.buf);
734 strbuf_addstr(temp_tab, ".temp.XXXXXX");
735
736 tab_fd = mkstemp(temp_tab->buf);
737 wr = reftable_new_writer(reftable_fd_write, &tab_fd, &st->config);
738
739 err = stack_write_compact(st, wr, first, last, config);
740 if (err < 0)
741 goto done;
742 err = reftable_writer_close(wr);
743 if (err < 0)
744 goto done;
745
746 err = close(tab_fd);
747 tab_fd = 0;
748
749 done:
750 reftable_writer_free(wr);
751 if (tab_fd > 0) {
752 close(tab_fd);
753 tab_fd = 0;
754 }
755 if (err != 0 && temp_tab->len > 0) {
756 unlink(temp_tab->buf);
757 strbuf_release(temp_tab);
758 }
759 strbuf_release(&next_name);
760 return err;
761 }
762
763 static int stack_write_compact(struct reftable_stack *st,
764 struct reftable_writer *wr, int first, int last,
765 struct reftable_log_expiry_config *config)
766 {
767 int subtabs_len = last - first + 1;
768 struct reftable_table *subtabs = reftable_calloc(
769 sizeof(struct reftable_table) * (last - first + 1));
770 struct reftable_merged_table *mt = NULL;
771 int err = 0;
772 struct reftable_iterator it = { NULL };
773 struct reftable_ref_record ref = { NULL };
774 struct reftable_log_record log = { NULL };
775
776 uint64_t entries = 0;
777
778 int i = 0, j = 0;
779 for (i = first, j = 0; i <= last; i++) {
780 struct reftable_reader *t = st->readers[i];
781 reftable_table_from_reader(&subtabs[j++], t);
782 st->stats.bytes += t->size;
783 }
784 reftable_writer_set_limits(wr, st->readers[first]->min_update_index,
785 st->readers[last]->max_update_index);
786
787 err = reftable_new_merged_table(&mt, subtabs, subtabs_len,
788 st->config.hash_id);
789 if (err < 0) {
790 reftable_free(subtabs);
791 goto done;
792 }
793
794 err = reftable_merged_table_seek_ref(mt, &it, "");
795 if (err < 0)
796 goto done;
797
798 while (1) {
799 err = reftable_iterator_next_ref(&it, &ref);
800 if (err > 0) {
801 err = 0;
802 break;
803 }
804 if (err < 0) {
805 break;
806 }
807
808 if (first == 0 && reftable_ref_record_is_deletion(&ref)) {
809 continue;
810 }
811
812 err = reftable_writer_add_ref(wr, &ref);
813 if (err < 0) {
814 break;
815 }
816 entries++;
817 }
818 reftable_iterator_destroy(&it);
819
820 err = reftable_merged_table_seek_log(mt, &it, "");
821 if (err < 0)
822 goto done;
823
824 while (1) {
825 err = reftable_iterator_next_log(&it, &log);
826 if (err > 0) {
827 err = 0;
828 break;
829 }
830 if (err < 0) {
831 break;
832 }
833 if (first == 0 && reftable_log_record_is_deletion(&log)) {
834 continue;
835 }
836
837 if (config && config->min_update_index > 0 &&
838 log.update_index < config->min_update_index) {
839 continue;
840 }
841
842 if (config && config->time > 0 &&
843 log.value.update.time < config->time) {
844 continue;
845 }
846
847 err = reftable_writer_add_log(wr, &log);
848 if (err < 0) {
849 break;
850 }
851 entries++;
852 }
853
854 done:
855 reftable_iterator_destroy(&it);
856 if (mt) {
857 merged_table_release(mt);
858 reftable_merged_table_free(mt);
859 }
860 reftable_ref_record_release(&ref);
861 reftable_log_record_release(&log);
862 st->stats.entries_written += entries;
863 return err;
864 }
865
866 /* < 0: error. 0 == OK, > 0 attempt failed; could retry. */
867 static int stack_compact_range(struct reftable_stack *st, int first, int last,
868 struct reftable_log_expiry_config *expiry)
869 {
870 struct strbuf temp_tab_file_name = STRBUF_INIT;
871 struct strbuf new_table_name = STRBUF_INIT;
872 struct strbuf lock_file_name = STRBUF_INIT;
873 struct strbuf ref_list_contents = STRBUF_INIT;
874 struct strbuf new_table_path = STRBUF_INIT;
875 int err = 0;
876 int have_lock = 0;
877 int lock_file_fd = -1;
878 int compact_count = last - first + 1;
879 char **listp = NULL;
880 char **delete_on_success =
881 reftable_calloc(sizeof(char *) * (compact_count + 1));
882 char **subtable_locks =
883 reftable_calloc(sizeof(char *) * (compact_count + 1));
884 int i = 0;
885 int j = 0;
886 int is_empty_table = 0;
887
888 if (first > last || (!expiry && first == last)) {
889 err = 0;
890 goto done;
891 }
892
893 st->stats.attempts++;
894
895 strbuf_reset(&lock_file_name);
896 strbuf_addstr(&lock_file_name, st->list_file);
897 strbuf_addstr(&lock_file_name, ".lock");
898
899 lock_file_fd =
900 open(lock_file_name.buf, O_EXCL | O_CREAT | O_WRONLY, 0666);
901 if (lock_file_fd < 0) {
902 if (errno == EEXIST) {
903 err = 1;
904 } else {
905 err = REFTABLE_IO_ERROR;
906 }
907 goto done;
908 }
909 /* Don't want to write to the lock for now. */
910 close(lock_file_fd);
911 lock_file_fd = -1;
912
913 have_lock = 1;
914 err = stack_uptodate(st);
915 if (err != 0)
916 goto done;
917
918 for (i = first, j = 0; i <= last; i++) {
919 struct strbuf subtab_file_name = STRBUF_INIT;
920 struct strbuf subtab_lock = STRBUF_INIT;
921 int sublock_file_fd = -1;
922
923 stack_filename(&subtab_file_name, st,
924 reader_name(st->readers[i]));
925
926 strbuf_reset(&subtab_lock);
927 strbuf_addbuf(&subtab_lock, &subtab_file_name);
928 strbuf_addstr(&subtab_lock, ".lock");
929
930 sublock_file_fd = open(subtab_lock.buf,
931 O_EXCL | O_CREAT | O_WRONLY, 0666);
932 if (sublock_file_fd >= 0) {
933 close(sublock_file_fd);
934 } else if (sublock_file_fd < 0) {
935 if (errno == EEXIST) {
936 err = 1;
937 } else {
938 err = REFTABLE_IO_ERROR;
939 }
940 }
941
942 subtable_locks[j] = subtab_lock.buf;
943 delete_on_success[j] = subtab_file_name.buf;
944 j++;
945
946 if (err != 0)
947 goto done;
948 }
949
950 err = unlink(lock_file_name.buf);
951 if (err < 0)
952 goto done;
953 have_lock = 0;
954
955 err = stack_compact_locked(st, first, last, &temp_tab_file_name,
956 expiry);
957 /* Compaction + tombstones can create an empty table out of non-empty
958 * tables. */
959 is_empty_table = (err == REFTABLE_EMPTY_TABLE_ERROR);
960 if (is_empty_table) {
961 err = 0;
962 }
963 if (err < 0)
964 goto done;
965
966 lock_file_fd =
967 open(lock_file_name.buf, O_EXCL | O_CREAT | O_WRONLY, 0666);
968 if (lock_file_fd < 0) {
969 if (errno == EEXIST) {
970 err = 1;
971 } else {
972 err = REFTABLE_IO_ERROR;
973 }
974 goto done;
975 }
976 have_lock = 1;
977 if (st->config.default_permissions) {
978 if (chmod(lock_file_name.buf, st->config.default_permissions) < 0) {
979 err = REFTABLE_IO_ERROR;
980 goto done;
981 }
982 }
983
984 format_name(&new_table_name, st->readers[first]->min_update_index,
985 st->readers[last]->max_update_index);
986 strbuf_addstr(&new_table_name, ".ref");
987
988 stack_filename(&new_table_path, st, new_table_name.buf);
989
990 if (!is_empty_table) {
991 /* retry? */
992 err = rename(temp_tab_file_name.buf, new_table_path.buf);
993 if (err < 0) {
994 err = REFTABLE_IO_ERROR;
995 goto done;
996 }
997 }
998
999 for (i = 0; i < first; i++) {
1000 strbuf_addstr(&ref_list_contents, st->readers[i]->name);
1001 strbuf_addstr(&ref_list_contents, "\n");
1002 }
1003 if (!is_empty_table) {
1004 strbuf_addbuf(&ref_list_contents, &new_table_name);
1005 strbuf_addstr(&ref_list_contents, "\n");
1006 }
1007 for (i = last + 1; i < st->merged->stack_len; i++) {
1008 strbuf_addstr(&ref_list_contents, st->readers[i]->name);
1009 strbuf_addstr(&ref_list_contents, "\n");
1010 }
1011
1012 err = write_in_full(lock_file_fd, ref_list_contents.buf, ref_list_contents.len);
1013 if (err < 0) {
1014 err = REFTABLE_IO_ERROR;
1015 unlink(new_table_path.buf);
1016 goto done;
1017 }
1018 err = close(lock_file_fd);
1019 lock_file_fd = -1;
1020 if (err < 0) {
1021 err = REFTABLE_IO_ERROR;
1022 unlink(new_table_path.buf);
1023 goto done;
1024 }
1025
1026 err = rename(lock_file_name.buf, st->list_file);
1027 if (err < 0) {
1028 err = REFTABLE_IO_ERROR;
1029 unlink(new_table_path.buf);
1030 goto done;
1031 }
1032 have_lock = 0;
1033
1034 /* Reload the stack before deleting. On windows, we can only delete the
1035 files after we closed them.
1036 */
1037 err = reftable_stack_reload_maybe_reuse(st, first < last);
1038
1039 listp = delete_on_success;
1040 while (*listp) {
1041 if (strcmp(*listp, new_table_path.buf)) {
1042 unlink(*listp);
1043 }
1044 listp++;
1045 }
1046
1047 done:
1048 free_names(delete_on_success);
1049
1050 listp = subtable_locks;
1051 while (*listp) {
1052 unlink(*listp);
1053 listp++;
1054 }
1055 free_names(subtable_locks);
1056 if (lock_file_fd >= 0) {
1057 close(lock_file_fd);
1058 lock_file_fd = -1;
1059 }
1060 if (have_lock) {
1061 unlink(lock_file_name.buf);
1062 }
1063 strbuf_release(&new_table_name);
1064 strbuf_release(&new_table_path);
1065 strbuf_release(&ref_list_contents);
1066 strbuf_release(&temp_tab_file_name);
1067 strbuf_release(&lock_file_name);
1068 return err;
1069 }
1070
1071 int reftable_stack_compact_all(struct reftable_stack *st,
1072 struct reftable_log_expiry_config *config)
1073 {
1074 return stack_compact_range(st, 0, st->merged->stack_len - 1, config);
1075 }
1076
1077 static int stack_compact_range_stats(struct reftable_stack *st, int first,
1078 int last,
1079 struct reftable_log_expiry_config *config)
1080 {
1081 int err = stack_compact_range(st, first, last, config);
1082 if (err > 0) {
1083 st->stats.failures++;
1084 }
1085 return err;
1086 }
1087
1088 static int segment_size(struct segment *s)
1089 {
1090 return s->end - s->start;
1091 }
1092
1093 int fastlog2(uint64_t sz)
1094 {
1095 int l = 0;
1096 if (sz == 0)
1097 return 0;
1098 for (; sz; sz /= 2) {
1099 l++;
1100 }
1101 return l - 1;
1102 }
1103
1104 struct segment *sizes_to_segments(int *seglen, uint64_t *sizes, int n)
1105 {
1106 struct segment *segs = reftable_calloc(sizeof(struct segment) * n);
1107 int next = 0;
1108 struct segment cur = { 0 };
1109 int i = 0;
1110
1111 if (n == 0) {
1112 *seglen = 0;
1113 return segs;
1114 }
1115 for (i = 0; i < n; i++) {
1116 int log = fastlog2(sizes[i]);
1117 if (cur.log != log && cur.bytes > 0) {
1118 struct segment fresh = {
1119 .start = i,
1120 };
1121
1122 segs[next++] = cur;
1123 cur = fresh;
1124 }
1125
1126 cur.log = log;
1127 cur.end = i + 1;
1128 cur.bytes += sizes[i];
1129 }
1130 segs[next++] = cur;
1131 *seglen = next;
1132 return segs;
1133 }
1134
1135 struct segment suggest_compaction_segment(uint64_t *sizes, int n)
1136 {
1137 int seglen = 0;
1138 struct segment *segs = sizes_to_segments(&seglen, sizes, n);
1139 struct segment min_seg = {
1140 .log = 64,
1141 };
1142 int i = 0;
1143 for (i = 0; i < seglen; i++) {
1144 if (segment_size(&segs[i]) == 1) {
1145 continue;
1146 }
1147
1148 if (segs[i].log < min_seg.log) {
1149 min_seg = segs[i];
1150 }
1151 }
1152
1153 while (min_seg.start > 0) {
1154 int prev = min_seg.start - 1;
1155 if (fastlog2(min_seg.bytes) < fastlog2(sizes[prev])) {
1156 break;
1157 }
1158
1159 min_seg.start = prev;
1160 min_seg.bytes += sizes[prev];
1161 }
1162
1163 reftable_free(segs);
1164 return min_seg;
1165 }
1166
1167 static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st)
1168 {
1169 uint64_t *sizes =
1170 reftable_calloc(sizeof(uint64_t) * st->merged->stack_len);
1171 int version = (st->config.hash_id == GIT_SHA1_FORMAT_ID) ? 1 : 2;
1172 int overhead = header_size(version) - 1;
1173 int i = 0;
1174 for (i = 0; i < st->merged->stack_len; i++) {
1175 sizes[i] = st->readers[i]->size - overhead;
1176 }
1177 return sizes;
1178 }
1179
1180 int reftable_stack_auto_compact(struct reftable_stack *st)
1181 {
1182 uint64_t *sizes = stack_table_sizes_for_compaction(st);
1183 struct segment seg =
1184 suggest_compaction_segment(sizes, st->merged->stack_len);
1185 reftable_free(sizes);
1186 if (segment_size(&seg) > 0)
1187 return stack_compact_range_stats(st, seg.start, seg.end - 1,
1188 NULL);
1189
1190 return 0;
1191 }
1192
1193 struct reftable_compaction_stats *
1194 reftable_stack_compaction_stats(struct reftable_stack *st)
1195 {
1196 return &st->stats;
1197 }
1198
1199 int reftable_stack_read_ref(struct reftable_stack *st, const char *refname,
1200 struct reftable_ref_record *ref)
1201 {
1202 struct reftable_table tab = { NULL };
1203 reftable_table_from_merged_table(&tab, reftable_stack_merged_table(st));
1204 return reftable_table_read_ref(&tab, refname, ref);
1205 }
1206
1207 int reftable_stack_read_log(struct reftable_stack *st, const char *refname,
1208 struct reftable_log_record *log)
1209 {
1210 struct reftable_iterator it = { NULL };
1211 struct reftable_merged_table *mt = reftable_stack_merged_table(st);
1212 int err = reftable_merged_table_seek_log(mt, &it, refname);
1213 if (err)
1214 goto done;
1215
1216 err = reftable_iterator_next_log(&it, log);
1217 if (err)
1218 goto done;
1219
1220 if (strcmp(log->refname, refname) ||
1221 reftable_log_record_is_deletion(log)) {
1222 err = 1;
1223 goto done;
1224 }
1225
1226 done:
1227 if (err) {
1228 reftable_log_record_release(log);
1229 }
1230 reftable_iterator_destroy(&it);
1231 return err;
1232 }
1233
1234 static int stack_check_addition(struct reftable_stack *st,
1235 const char *new_tab_name)
1236 {
1237 int err = 0;
1238 struct reftable_block_source src = { NULL };
1239 struct reftable_reader *rd = NULL;
1240 struct reftable_table tab = { NULL };
1241 struct reftable_ref_record *refs = NULL;
1242 struct reftable_iterator it = { NULL };
1243 int cap = 0;
1244 int len = 0;
1245 int i = 0;
1246
1247 if (st->config.skip_name_check)
1248 return 0;
1249
1250 err = reftable_block_source_from_file(&src, new_tab_name);
1251 if (err < 0)
1252 goto done;
1253
1254 err = reftable_new_reader(&rd, &src, new_tab_name);
1255 if (err < 0)
1256 goto done;
1257
1258 err = reftable_reader_seek_ref(rd, &it, "");
1259 if (err > 0) {
1260 err = 0;
1261 goto done;
1262 }
1263 if (err < 0)
1264 goto done;
1265
1266 while (1) {
1267 struct reftable_ref_record ref = { NULL };
1268 err = reftable_iterator_next_ref(&it, &ref);
1269 if (err > 0) {
1270 break;
1271 }
1272 if (err < 0)
1273 goto done;
1274
1275 if (len >= cap) {
1276 cap = 2 * cap + 1;
1277 refs = reftable_realloc(refs, cap * sizeof(refs[0]));
1278 }
1279
1280 refs[len++] = ref;
1281 }
1282
1283 reftable_table_from_merged_table(&tab, reftable_stack_merged_table(st));
1284
1285 err = validate_ref_record_addition(tab, refs, len);
1286
1287 done:
1288 for (i = 0; i < len; i++) {
1289 reftable_ref_record_release(&refs[i]);
1290 }
1291
1292 free(refs);
1293 reftable_iterator_destroy(&it);
1294 reftable_reader_free(rd);
1295 return err;
1296 }
1297
1298 static int is_table_name(const char *s)
1299 {
1300 const char *dot = strrchr(s, '.');
1301 return dot && !strcmp(dot, ".ref");
1302 }
1303
1304 static void remove_maybe_stale_table(struct reftable_stack *st, uint64_t max,
1305 const char *name)
1306 {
1307 int err = 0;
1308 uint64_t update_idx = 0;
1309 struct reftable_block_source src = { NULL };
1310 struct reftable_reader *rd = NULL;
1311 struct strbuf table_path = STRBUF_INIT;
1312 stack_filename(&table_path, st, name);
1313
1314 err = reftable_block_source_from_file(&src, table_path.buf);
1315 if (err < 0)
1316 goto done;
1317
1318 err = reftable_new_reader(&rd, &src, name);
1319 if (err < 0)
1320 goto done;
1321
1322 update_idx = reftable_reader_max_update_index(rd);
1323 reftable_reader_free(rd);
1324
1325 if (update_idx <= max) {
1326 unlink(table_path.buf);
1327 }
1328 done:
1329 strbuf_release(&table_path);
1330 }
1331
1332 static int reftable_stack_clean_locked(struct reftable_stack *st)
1333 {
1334 uint64_t max = reftable_merged_table_max_update_index(
1335 reftable_stack_merged_table(st));
1336 DIR *dir = opendir(st->reftable_dir);
1337 struct dirent *d = NULL;
1338 if (!dir) {
1339 return REFTABLE_IO_ERROR;
1340 }
1341
1342 while ((d = readdir(dir))) {
1343 int i = 0;
1344 int found = 0;
1345 if (!is_table_name(d->d_name))
1346 continue;
1347
1348 for (i = 0; !found && i < st->readers_len; i++) {
1349 found = !strcmp(reader_name(st->readers[i]), d->d_name);
1350 }
1351 if (found)
1352 continue;
1353
1354 remove_maybe_stale_table(st, max, d->d_name);
1355 }
1356
1357 closedir(dir);
1358 return 0;
1359 }
1360
1361 int reftable_stack_clean(struct reftable_stack *st)
1362 {
1363 struct reftable_addition *add = NULL;
1364 int err = reftable_stack_new_addition(&add, st);
1365 if (err < 0) {
1366 goto done;
1367 }
1368
1369 err = reftable_stack_reload(st);
1370 if (err < 0) {
1371 goto done;
1372 }
1373
1374 err = reftable_stack_clean_locked(st);
1375
1376 done:
1377 reftable_addition_destroy(add);
1378 return err;
1379 }
1380
1381 int reftable_stack_print_directory(const char *stackdir, uint32_t hash_id)
1382 {
1383 struct reftable_stack *stack = NULL;
1384 struct reftable_write_options cfg = { .hash_id = hash_id };
1385 struct reftable_merged_table *merged = NULL;
1386 struct reftable_table table = { NULL };
1387
1388 int err = reftable_new_stack(&stack, stackdir, cfg);
1389 if (err < 0)
1390 goto done;
1391
1392 merged = reftable_stack_merged_table(stack);
1393 reftable_table_from_merged_table(&table, merged);
1394 err = reftable_table_print(&table);
1395 done:
1396 if (stack)
1397 reftable_stack_destroy(stack);
1398 return err;
1399 }