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