Raw
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 "constants.h"
13 #include "merged.h"
14 #include "reftable-error.h"
15 #include "reftable-record.h"
16 #include "reftable-merged.h"
17 #include "table.h"
18 #include "writer.h"
19
20 static int stack_filename(struct reftable_buf *dest, struct reftable_stack *st,
21 const char *name)
22 {
23 int err;
24 reftable_buf_reset(dest);
25 if ((err = reftable_buf_addstr(dest, st->reftable_dir)) < 0 ||
26 (err = reftable_buf_addstr(dest, "/")) < 0 ||
27 (err = reftable_buf_addstr(dest, name)) < 0)
28 return err;
29 return 0;
30 }
31
32 static ssize_t reftable_write_data(int fd, const void *data, size_t size)
33 {
34 size_t total_written = 0;
35 const char *p = data;
36
37 while (total_written < size) {
38 ssize_t bytes_written = write(fd, p, size - total_written);
39 if (bytes_written < 0 && (errno == EAGAIN || errno == EINTR))
40 continue;
41 if (bytes_written < 0)
42 return REFTABLE_IO_ERROR;
43
44 total_written += bytes_written;
45 p += bytes_written;
46 }
47
48 return total_written;
49 }
50
51 struct fd_writer {
52 const struct reftable_write_options *opts;
53 int fd;
54 };
55
56 static ssize_t fd_writer_write(void *arg, const void *data, size_t sz)
57 {
58 struct fd_writer *writer = arg;
59 return reftable_write_data(writer->fd, data, sz);
60 }
61
62 static int fd_writer_flush(void *arg)
63 {
64 struct fd_writer *writer = arg;
65 return fsync(writer->fd);
66 }
67
68 static int fd_read_lines(int fd, char ***namesp)
69 {
70 char *buf = NULL;
71 int err = 0;
72 off_t size;
73
74 size = lseek(fd, 0, SEEK_END);
75 if (size < 0) {
76 err = REFTABLE_IO_ERROR;
77 goto done;
78 }
79
80 err = lseek(fd, 0, SEEK_SET);
81 if (err < 0) {
82 err = REFTABLE_IO_ERROR;
83 goto done;
84 }
85
86 REFTABLE_ALLOC_ARRAY(buf, size + 1);
87 if (!buf) {
88 err = REFTABLE_OUT_OF_MEMORY_ERROR;
89 goto done;
90 }
91
92 for (off_t total_read = 0; total_read < size; ) {
93 ssize_t bytes_read = read(fd, buf + total_read, size - total_read);
94 if (bytes_read < 0 && (errno == EAGAIN || errno == EINTR))
95 continue;
96 if (bytes_read < 0 || !bytes_read) {
97 err = REFTABLE_IO_ERROR;
98 goto done;
99 }
100
101 total_read += bytes_read;
102 }
103 buf[size] = 0;
104
105 err = parse_names(buf, size, namesp);
106 done:
107 reftable_free(buf);
108 return err;
109 }
110
111 int 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 REFTABLE_CALLOC_ARRAY(*namesp, 1);
118 if (!*namesp)
119 return REFTABLE_OUT_OF_MEMORY_ERROR;
120 return 0;
121 }
122
123 return REFTABLE_IO_ERROR;
124 }
125 err = fd_read_lines(fd, namesp);
126 close(fd);
127 return err;
128 }
129
130 int reftable_stack_init_ref_iterator(struct reftable_stack *st,
131 struct reftable_iterator *it)
132 {
133 return merged_table_init_iter(reftable_stack_merged_table(st),
134 it, REFTABLE_BLOCK_TYPE_REF);
135 }
136
137 int reftable_stack_init_log_iterator(struct reftable_stack *st,
138 struct reftable_iterator *it)
139 {
140 return merged_table_init_iter(reftable_stack_merged_table(st),
141 it, REFTABLE_BLOCK_TYPE_LOG);
142 }
143
144 struct reftable_merged_table *
145 reftable_stack_merged_table(struct reftable_stack *st)
146 {
147 return st->merged;
148 }
149
150 static int has_name(char **names, const char *name)
151 {
152 while (*names) {
153 if (!strcmp(*names, name))
154 return 1;
155 names++;
156 }
157 return 0;
158 }
159
160 /* Close and free the stack */
161 void reftable_stack_destroy(struct reftable_stack *st)
162 {
163 char **names = NULL;
164 int err = 0;
165
166 if (!st)
167 return;
168
169 if (st->merged) {
170 reftable_merged_table_free(st->merged);
171 st->merged = NULL;
172 }
173
174 if (st->list_file)
175 err = read_lines(st->list_file, &names);
176 if (err < 0) {
177 REFTABLE_FREE_AND_NULL(names);
178 }
179
180 if (st->tables) {
181 struct reftable_buf filename = REFTABLE_BUF_INIT;
182
183 for (size_t i = 0; i < st->tables_len; i++) {
184 const char *name = reftable_table_name(st->tables[i]);
185 int try_unlinking = 1;
186
187 reftable_buf_reset(&filename);
188 if (names && !has_name(names, name)) {
189 if (stack_filename(&filename, st, name) < 0)
190 try_unlinking = 0;
191 }
192 reftable_table_decref(st->tables[i]);
193
194 if (try_unlinking && filename.len) {
195 /* On Windows, can only unlink after closing. */
196 unlink(filename.buf);
197 }
198 }
199
200 reftable_buf_release(&filename);
201 st->tables_len = 0;
202 REFTABLE_FREE_AND_NULL(st->tables);
203 }
204
205 if (st->list_fd >= 0) {
206 close(st->list_fd);
207 st->list_fd = -1;
208 }
209
210 REFTABLE_FREE_AND_NULL(st->list_file);
211 REFTABLE_FREE_AND_NULL(st->reftable_dir);
212 reftable_free(st);
213 free_names(names);
214 }
215
216 static struct reftable_table **stack_copy_tables(struct reftable_stack *st,
217 size_t cur_len)
218 {
219 struct reftable_table **cur = reftable_calloc(cur_len, sizeof(*cur));
220 if (!cur)
221 return NULL;
222 for (size_t i = 0; i < cur_len; i++)
223 cur[i] = st->tables[i];
224 return cur;
225 }
226
227 static int reftable_stack_reload_once(struct reftable_stack *st,
228 const char **names,
229 int reuse_open)
230 {
231 size_t cur_len = !st->merged ? 0 : st->merged->tables_len;
232 struct reftable_table **cur = NULL;
233 struct reftable_table **reused = NULL;
234 struct reftable_table **new_tables = NULL;
235 size_t reused_len = 0, reused_alloc = 0, names_len;
236 size_t new_tables_len = 0;
237 struct reftable_merged_table *new_merged = NULL;
238 struct reftable_buf table_path = REFTABLE_BUF_INIT;
239 int err = 0;
240 size_t i;
241
242 if (cur_len) {
243 cur = stack_copy_tables(st, cur_len);
244 if (!cur) {
245 err = REFTABLE_OUT_OF_MEMORY_ERROR;
246 goto done;
247 }
248 }
249
250 names_len = names_length(names);
251
252 if (names_len) {
253 new_tables = reftable_calloc(names_len, sizeof(*new_tables));
254 if (!new_tables) {
255 err = REFTABLE_OUT_OF_MEMORY_ERROR;
256 goto done;
257 }
258 }
259
260 while (*names) {
261 struct reftable_table *table = NULL;
262 const char *name = *names++;
263
264 /* this is linear; we assume compaction keeps the number of
265 tables under control so this is not quadratic. */
266 for (i = 0; reuse_open && i < cur_len; i++) {
267 if (cur[i] && 0 == strcmp(cur[i]->name, name)) {
268 table = cur[i];
269 cur[i] = NULL;
270
271 /*
272 * When reloading the stack fails, we end up
273 * releasing all new tables. This also
274 * includes the reused tables, even though
275 * they are still in used by the old stack. We
276 * thus need to keep them alive here, which we
277 * do by bumping their refcount.
278 */
279 REFTABLE_ALLOC_GROW_OR_NULL(reused,
280 reused_len + 1,
281 reused_alloc);
282 if (!reused) {
283 err = REFTABLE_OUT_OF_MEMORY_ERROR;
284 goto done;
285 }
286 reused[reused_len++] = table;
287 reftable_table_incref(table);
288 break;
289 }
290 }
291
292 if (!table) {
293 struct reftable_block_source src = { NULL };
294
295 err = stack_filename(&table_path, st, name);
296 if (err < 0)
297 goto done;
298
299 err = reftable_block_source_from_file(&src,
300 table_path.buf);
301 if (err < 0)
302 goto done;
303
304 err = reftable_table_new(&table, &src, name);
305 if (err < 0)
306 goto done;
307 }
308
309 new_tables[new_tables_len] = table;
310 new_tables_len++;
311 }
312
313 /* success! */
314 err = reftable_merged_table_new(&new_merged, new_tables,
315 new_tables_len, st->opts.hash_id);
316 if (err < 0)
317 goto done;
318
319 /*
320 * Close the old, non-reused tables and proactively try to unlink
321 * them. This is done for systems like Windows, where the underlying
322 * file of such an open table wouldn't have been possible to be
323 * unlinked by the compacting process.
324 */
325 for (i = 0; i < cur_len; i++) {
326 if (cur[i]) {
327 const char *name = reftable_table_name(cur[i]);
328
329 err = stack_filename(&table_path, st, name);
330 if (err < 0)
331 goto done;
332
333 reftable_table_decref(cur[i]);
334 unlink(table_path.buf);
335 }
336 }
337
338 /* Update the stack to point to the new tables. */
339 if (st->merged)
340 reftable_merged_table_free(st->merged);
341 new_merged->suppress_deletions = st->opts.suppress_deletions;
342 st->merged = new_merged;
343
344 if (st->tables)
345 reftable_free(st->tables);
346 st->tables = new_tables;
347 st->tables_len = new_tables_len;
348 new_tables = NULL;
349 new_tables_len = 0;
350
351 /*
352 * Decrement the refcount of reused tables again. This only needs to
353 * happen on the successful case, because on the unsuccessful one we
354 * decrement their refcount via `new_tables`.
355 */
356 for (i = 0; i < reused_len; i++)
357 reftable_table_decref(reused[i]);
358
359 done:
360 for (i = 0; i < new_tables_len; i++)
361 reftable_table_decref(new_tables[i]);
362 reftable_free(new_tables);
363 reftable_free(reused);
364 reftable_free(cur);
365 reftable_buf_release(&table_path);
366 return err;
367 }
368
369 static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st,
370 int reuse_open)
371 {
372 char **names = NULL, **names_after = NULL;
373 uint64_t deadline;
374 int64_t delay = 0;
375 int tries = 0, err;
376 int fd = -1;
377
378 deadline = reftable_time_ms() + 3000;
379
380 while (1) {
381 uint64_t now = reftable_time_ms();
382
383 /*
384 * Only look at deadlines after the first few times. This
385 * simplifies debugging in GDB.
386 */
387 tries++;
388 if (tries > 3 && now >= deadline)
389 goto out;
390
391 fd = open(st->list_file, O_RDONLY);
392 if (fd < 0) {
393 if (errno != ENOENT) {
394 err = REFTABLE_IO_ERROR;
395 goto out;
396 }
397
398 REFTABLE_CALLOC_ARRAY(names, 1);
399 if (!names) {
400 err = REFTABLE_OUT_OF_MEMORY_ERROR;
401 goto out;
402 }
403 } else {
404 err = fd_read_lines(fd, &names);
405 if (err < 0)
406 goto out;
407 }
408
409 err = reftable_stack_reload_once(st, (const char **) names, reuse_open);
410 if (!err)
411 break;
412 if (err != REFTABLE_NOT_EXIST_ERROR)
413 goto out;
414
415 /*
416 * REFTABLE_NOT_EXIST_ERROR can be caused by a concurrent
417 * writer. Check if there was one by checking if the name list
418 * changed.
419 */
420 err = read_lines(st->list_file, &names_after);
421 if (err < 0)
422 goto out;
423 if (names_equal((const char **) names_after,
424 (const char **) names)) {
425 err = REFTABLE_NOT_EXIST_ERROR;
426 goto out;
427 }
428
429 free_names(names);
430 names = NULL;
431 free_names(names_after);
432 names_after = NULL;
433 close(fd);
434 fd = -1;
435
436 delay = delay + (delay * reftable_rand()) / UINT32_MAX + 1;
437 poll(NULL, 0, delay);
438 }
439
440 out:
441 /*
442 * Invalidate the stat cache. It is sufficient to only close the file
443 * descriptor and keep the cached stat info because we never use the
444 * latter when the former is negative.
445 */
446 if (st->list_fd >= 0) {
447 close(st->list_fd);
448 st->list_fd = -1;
449 }
450
451 /*
452 * Cache stat information in case it provides a useful signal to us.
453 * According to POSIX, "The st_ino and st_dev fields taken together
454 * uniquely identify the file within the system." That being said,
455 * Windows is not POSIX compliant and we do not have these fields
456 * available. So the information we have there is insufficient to
457 * determine whether two file descriptors point to the same file.
458 *
459 * While we could fall back to using other signals like the file's
460 * mtime, those are not sufficient to avoid races. We thus refrain from
461 * using the stat cache on such systems and fall back to the secondary
462 * caching mechanism, which is to check whether contents of the file
463 * have changed.
464 *
465 * On other systems which are POSIX compliant we must keep the file
466 * descriptor open. This is to avoid a race condition where two
467 * processes access the reftable stack at the same point in time:
468 *
469 * 1. A reads the reftable stack and caches its stat info.
470 *
471 * 2. B updates the stack, appending a new table to "tables.list".
472 * This will both use a new inode and result in a different file
473 * size, thus invalidating A's cache in theory.
474 *
475 * 3. B decides to auto-compact the stack and merges two tables. The
476 * file size now matches what A has cached again. Furthermore, the
477 * filesystem may decide to recycle the inode number of the file
478 * we have replaced in (2) because it is not in use anymore.
479 *
480 * 4. A reloads the reftable stack. Neither the inode number nor the
481 * file size changed. If the timestamps did not change either then
482 * we think the cached copy of our stack is up-to-date.
483 *
484 * By keeping the file descriptor open the inode number cannot be
485 * recycled, mitigating the race.
486 */
487 if (!err && fd >= 0 && !fstat(fd, &st->list_st) &&
488 st->list_st.st_dev && st->list_st.st_ino) {
489 st->list_fd = fd;
490 fd = -1;
491 }
492
493 if (fd >= 0)
494 close(fd);
495 free_names(names);
496 free_names(names_after);
497
498 if (st->opts.on_reload)
499 st->opts.on_reload(st->opts.on_reload_payload);
500
501 return err;
502 }
503
504 int reftable_new_stack(struct reftable_stack **dest, const char *dir,
505 const struct reftable_stack_options *_opts)
506 {
507 struct reftable_buf list_file_name = REFTABLE_BUF_INIT;
508 struct reftable_stack_options opts = { 0 };
509 struct reftable_stack *p;
510 int err;
511
512 p = reftable_calloc(1, sizeof(*p));
513 if (!p) {
514 err = REFTABLE_OUT_OF_MEMORY_ERROR;
515 goto out;
516 }
517
518 if (_opts)
519 opts = *_opts;
520 if (opts.hash_id == 0)
521 opts.hash_id = REFTABLE_HASH_SHA1;
522
523 *dest = NULL;
524
525 reftable_buf_reset(&list_file_name);
526 if ((err = reftable_buf_addstr(&list_file_name, dir)) < 0 ||
527 (err = reftable_buf_addstr(&list_file_name, "/tables.list")) < 0)
528 goto out;
529
530 p->list_file = reftable_buf_detach(&list_file_name);
531 p->list_fd = -1;
532 p->opts = opts;
533 p->reftable_dir = reftable_strdup(dir);
534 if (!p->reftable_dir) {
535 err = REFTABLE_OUT_OF_MEMORY_ERROR;
536 goto out;
537 }
538
539 err = reftable_stack_reload_maybe_reuse(p, 1);
540 if (err < 0)
541 goto out;
542
543 *dest = p;
544 err = 0;
545
546 out:
547 if (err < 0)
548 reftable_stack_destroy(p);
549 return err;
550 }
551
552 /*
553 * Check whether the given stack is up-to-date with what we have in memory.
554 * Returns 0 if so, 1 if the stack is out-of-date or a negative error code
555 * otherwise.
556 */
557 static int stack_uptodate(struct reftable_stack *st)
558 {
559 char **names = NULL;
560 int err;
561
562 /*
563 * When we have cached stat information available then we use it to
564 * verify whether the file has been rewritten.
565 *
566 * Note that we explicitly do not want to use `stat_validity_check()`
567 * and friends here because they may end up not comparing the `st_dev`
568 * and `st_ino` fields. These functions thus cannot guarantee that we
569 * indeed still have the same file.
570 */
571 if (st->list_fd >= 0) {
572 struct stat list_st;
573
574 if (stat(st->list_file, &list_st) < 0) {
575 /*
576 * It's fine for "tables.list" to not exist. In that
577 * case, we have to refresh when the loaded stack has
578 * any tables.
579 */
580 if (errno == ENOENT)
581 return !!st->tables_len;
582 return REFTABLE_IO_ERROR;
583 }
584
585 /*
586 * When "tables.list" refers to the same file we can assume
587 * that it didn't change. This is because we always use
588 * rename(3P) to update the file and never write to it
589 * directly.
590 */
591 if (st->list_st.st_dev == list_st.st_dev &&
592 st->list_st.st_ino == list_st.st_ino)
593 return 0;
594 }
595
596 err = read_lines(st->list_file, &names);
597 if (err < 0)
598 return err;
599
600 for (size_t i = 0; i < st->tables_len; i++) {
601 if (!names[i]) {
602 err = 1;
603 goto done;
604 }
605
606 if (strcmp(st->tables[i]->name, names[i])) {
607 err = 1;
608 goto done;
609 }
610 }
611
612 if (names[st->merged->tables_len]) {
613 err = 1;
614 goto done;
615 }
616
617 done:
618 free_names(names);
619 return err;
620 }
621
622 int reftable_stack_reload(struct reftable_stack *st)
623 {
624 int err = stack_uptodate(st);
625 if (err > 0)
626 return reftable_stack_reload_maybe_reuse(st, 1);
627 return err;
628 }
629
630 struct reftable_addition {
631 struct reftable_flock tables_list_lock;
632 struct reftable_stack *stack;
633 struct reftable_write_options opts;
634
635 char **new_tables;
636 size_t new_tables_len, new_tables_cap;
637 uint64_t next_update_index;
638 };
639
640 static void reftable_addition_close(struct reftable_addition *add)
641 {
642 struct reftable_buf nm = REFTABLE_BUF_INIT;
643 size_t i;
644
645 for (i = 0; i < add->new_tables_len; i++) {
646 if (!stack_filename(&nm, add->stack, add->new_tables[i]))
647 unlink(nm.buf);
648 reftable_free(add->new_tables[i]);
649 add->new_tables[i] = NULL;
650 }
651 reftable_free(add->new_tables);
652 add->new_tables = NULL;
653 add->new_tables_len = 0;
654 add->new_tables_cap = 0;
655
656 flock_release(&add->tables_list_lock);
657 reftable_buf_release(&nm);
658 }
659
660 static int reftable_stack_init_addition(struct reftable_addition *add,
661 struct reftable_stack *st,
662 const struct reftable_write_options *opts,
663 unsigned int flags)
664 {
665 struct reftable_buf lock_file_name = REFTABLE_BUF_INIT;
666 int err;
667
668 memset(add, 0, sizeof(*add));
669 add->stack = st;
670 if (opts)
671 add->opts = *opts;
672
673 err = flock_acquire(&add->tables_list_lock, st->list_file,
674 add->opts.lock_timeout_ms);
675 if (err < 0)
676 goto done;
677
678 if (add->opts.default_permissions) {
679 if (chmod(add->tables_list_lock.path,
680 add->opts.default_permissions) < 0) {
681 err = REFTABLE_IO_ERROR;
682 goto done;
683 }
684 }
685
686 err = stack_uptodate(st);
687 if (err < 0)
688 goto done;
689 if (err > 0 && flags & REFTABLE_STACK_NEW_ADDITION_RELOAD) {
690 err = reftable_stack_reload_maybe_reuse(add->stack, 1);
691 if (err)
692 goto done;
693 }
694 if (err > 0) {
695 err = REFTABLE_OUTDATED_ERROR;
696 goto done;
697 }
698
699 add->next_update_index = reftable_stack_next_update_index(st);
700 done:
701 if (err)
702 reftable_addition_close(add);
703 reftable_buf_release(&lock_file_name);
704 return err;
705 }
706
707 static int stack_try_add(struct reftable_stack *st,
708 int (*write_table)(struct reftable_writer *wr,
709 void *arg),
710 void *arg,
711 const struct reftable_write_options *opts,
712 unsigned flags)
713 {
714 struct reftable_addition add;
715 int err;
716
717 err = reftable_stack_init_addition(&add, st, opts, flags);
718 if (err < 0)
719 goto done;
720
721 err = reftable_addition_add(&add, write_table, arg);
722 if (err < 0)
723 goto done;
724
725 err = reftable_addition_commit(&add);
726 done:
727 reftable_addition_close(&add);
728 return err;
729 }
730
731 int reftable_stack_add(struct reftable_stack *st,
732 int (*write)(struct reftable_writer *wr, void *arg),
733 void *arg,
734 const struct reftable_write_options *opts,
735 unsigned flags)
736 {
737 int err = stack_try_add(st, write, arg, opts, flags);
738 if (err < 0) {
739 if (err == REFTABLE_OUTDATED_ERROR) {
740 /* Ignore error return, we want to propagate
741 REFTABLE_OUTDATED_ERROR.
742 */
743 reftable_stack_reload(st);
744 }
745 return err;
746 }
747
748 return 0;
749 }
750
751 static int format_name(struct reftable_buf *dest, uint64_t min, uint64_t max)
752 {
753 char buf[100];
754 uint32_t rnd = reftable_rand();
755 snprintf(buf, sizeof(buf), "0x%012" PRIx64 "-0x%012" PRIx64 "-%08x",
756 min, max, rnd);
757 reftable_buf_reset(dest);
758 return reftable_buf_addstr(dest, buf);
759 }
760
761 void reftable_addition_destroy(struct reftable_addition *add)
762 {
763 if (!add) {
764 return;
765 }
766 reftable_addition_close(add);
767 reftable_free(add);
768 }
769
770 int reftable_addition_commit(struct reftable_addition *add)
771 {
772 struct reftable_buf table_list = REFTABLE_BUF_INIT;
773 int err = 0;
774 size_t i;
775
776 if (add->new_tables_len == 0)
777 goto done;
778
779 for (i = 0; i < add->stack->merged->tables_len; i++) {
780 if ((err = reftable_buf_addstr(&table_list, add->stack->tables[i]->name)) < 0 ||
781 (err = reftable_buf_addstr(&table_list, "\n")) < 0)
782 goto done;
783 }
784 for (i = 0; i < add->new_tables_len; i++) {
785 if ((err = reftable_buf_addstr(&table_list, add->new_tables[i])) < 0 ||
786 (err = reftable_buf_addstr(&table_list, "\n")) < 0)
787 goto done;
788 }
789
790 err = reftable_write_data(add->tables_list_lock.fd,
791 table_list.buf, table_list.len);
792 reftable_buf_release(&table_list);
793 if (err < 0) {
794 err = REFTABLE_IO_ERROR;
795 goto done;
796 }
797
798 err = fsync(add->tables_list_lock.fd);
799 if (err < 0) {
800 err = REFTABLE_IO_ERROR;
801 goto done;
802 }
803
804 err = flock_commit(&add->tables_list_lock);
805 if (err < 0) {
806 err = REFTABLE_IO_ERROR;
807 goto done;
808 }
809
810 /* success, no more state to clean up. */
811 for (i = 0; i < add->new_tables_len; i++)
812 reftable_free(add->new_tables[i]);
813 reftable_free(add->new_tables);
814 add->new_tables = NULL;
815 add->new_tables_len = 0;
816 add->new_tables_cap = 0;
817
818 err = reftable_stack_reload_maybe_reuse(add->stack, 1);
819 if (err)
820 goto done;
821
822 if (!add->opts.disable_auto_compact) {
823 /*
824 * Auto-compact the stack to keep the number of tables in
825 * control. It is possible that a concurrent writer is already
826 * trying to compact parts of the stack, which would lead to a
827 * `REFTABLE_LOCK_ERROR` because parts of the stack are locked
828 * already. Similarly, the stack may have been rewritten by a
829 * concurrent writer, which causes `REFTABLE_OUTDATED_ERROR`.
830 * Both of these errors are benign, so we simply ignore them.
831 */
832 err = reftable_stack_auto_compact(add->stack, &add->opts);
833 if (err < 0 && err != REFTABLE_LOCK_ERROR &&
834 err != REFTABLE_OUTDATED_ERROR)
835 goto done;
836 err = 0;
837 }
838
839 done:
840 reftable_addition_close(add);
841 return err;
842 }
843
844 int reftable_stack_new_addition(struct reftable_addition **dest,
845 struct reftable_stack *st,
846 const struct reftable_write_options *opts,
847 unsigned int flags)
848 {
849 int err;
850
851 REFTABLE_CALLOC_ARRAY(*dest, 1);
852 if (!*dest)
853 return REFTABLE_OUT_OF_MEMORY_ERROR;
854
855 err = reftable_stack_init_addition(*dest, st, opts, flags);
856 if (err) {
857 reftable_free(*dest);
858 *dest = NULL;
859 }
860
861 return err;
862 }
863
864 int reftable_addition_add(struct reftable_addition *add,
865 int (*write_table)(struct reftable_writer *wr,
866 void *arg),
867 void *arg)
868 {
869 struct reftable_buf temp_tab_file_name = REFTABLE_BUF_INIT;
870 struct reftable_buf tab_file_name = REFTABLE_BUF_INIT;
871 struct reftable_buf next_name = REFTABLE_BUF_INIT;
872 struct reftable_writer *wr = NULL;
873 struct reftable_tmpfile tab_file = REFTABLE_TMPFILE_INIT;
874 struct fd_writer writer = {
875 .opts = &add->opts,
876 };
877 int err = 0;
878
879 reftable_buf_reset(&next_name);
880
881 err = format_name(&next_name, add->next_update_index, add->next_update_index);
882 if (err < 0)
883 goto done;
884
885 err = stack_filename(&temp_tab_file_name, add->stack, next_name.buf);
886 if (err < 0)
887 goto done;
888
889 err = reftable_buf_addstr(&temp_tab_file_name, ".temp.XXXXXX");
890 if (err < 0)
891 goto done;
892
893 err = tmpfile_from_pattern(&tab_file, temp_tab_file_name.buf);
894 if (err < 0)
895 goto done;
896 if (add->opts.default_permissions) {
897 if (chmod(tab_file.path,
898 add->opts.default_permissions)) {
899 err = REFTABLE_IO_ERROR;
900 goto done;
901 }
902 }
903
904 writer.fd = tab_file.fd;
905 err = reftable_writer_new(&wr, fd_writer_write, fd_writer_flush,
906 &writer, add->stack->opts.hash_id, &add->opts);
907 if (err < 0)
908 goto done;
909
910 err = write_table(wr, arg);
911 if (err < 0)
912 goto done;
913
914 err = reftable_writer_close(wr);
915 if (err == REFTABLE_EMPTY_TABLE_ERROR) {
916 err = 0;
917 goto done;
918 }
919 if (err < 0)
920 goto done;
921
922 err = tmpfile_close(&tab_file);
923 if (err < 0)
924 goto done;
925
926 if (wr->min_update_index < add->next_update_index) {
927 err = REFTABLE_API_ERROR;
928 goto done;
929 }
930
931 err = format_name(&next_name, wr->min_update_index, wr->max_update_index);
932 if (err < 0)
933 goto done;
934
935 err = reftable_buf_addstr(&next_name, ".ref");
936 if (err < 0)
937 goto done;
938
939 err = stack_filename(&tab_file_name, add->stack, next_name.buf);
940 if (err < 0)
941 goto done;
942
943 /*
944 On windows, this relies on rand() picking a unique destination name.
945 Maybe we should do retry loop as well?
946 */
947 err = tmpfile_rename(&tab_file, tab_file_name.buf);
948 if (err < 0)
949 goto done;
950
951 REFTABLE_ALLOC_GROW_OR_NULL(add->new_tables, add->new_tables_len + 1,
952 add->new_tables_cap);
953 if (!add->new_tables) {
954 err = REFTABLE_OUT_OF_MEMORY_ERROR;
955 goto done;
956 }
957 add->new_tables[add->new_tables_len++] = reftable_buf_detach(&next_name);
958
959 done:
960 tmpfile_delete(&tab_file);
961 reftable_buf_release(&temp_tab_file_name);
962 reftable_buf_release(&tab_file_name);
963 reftable_buf_release(&next_name);
964 reftable_writer_free(wr);
965 return err;
966 }
967
968 uint64_t reftable_stack_next_update_index(struct reftable_stack *st)
969 {
970 int sz = st->merged->tables_len;
971 if (sz > 0)
972 return reftable_table_max_update_index(st->tables[sz - 1]) +
973 1;
974 return 1;
975 }
976
977 static int stack_write_compact(struct reftable_stack *st,
978 struct reftable_writer *wr,
979 size_t first, size_t last,
980 struct reftable_log_expiry_config *config)
981 {
982 struct reftable_merged_table *mt = NULL;
983 struct reftable_iterator it = { NULL };
984 struct reftable_ref_record ref = { NULL };
985 struct reftable_log_record log = { NULL };
986 size_t subtabs_len = last - first + 1;
987 uint64_t entries = 0;
988 int err = 0;
989
990 for (size_t i = first; i <= last; i++)
991 st->stats.bytes += st->tables[i]->size;
992 err = reftable_writer_set_limits(wr, st->tables[first]->min_update_index,
993 st->tables[last]->max_update_index);
994 if (err < 0)
995 goto done;
996
997 err = reftable_merged_table_new(&mt, st->tables + first, subtabs_len,
998 st->opts.hash_id);
999 if (err < 0)
1000 goto done;
1001
1002 err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_REF);
1003 if (err < 0)
1004 goto done;
1005
1006 err = reftable_iterator_seek_ref(&it, "");
1007 if (err < 0)
1008 goto done;
1009
1010 while (1) {
1011 err = reftable_iterator_next_ref(&it, &ref);
1012 if (err > 0) {
1013 err = 0;
1014 break;
1015 }
1016 if (err < 0)
1017 goto done;
1018
1019 if (first == 0 && reftable_ref_record_is_deletion(&ref)) {
1020 continue;
1021 }
1022
1023 err = reftable_writer_add_ref(wr, &ref);
1024 if (err < 0)
1025 goto done;
1026 entries++;
1027 }
1028 reftable_iterator_destroy(&it);
1029
1030 err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_LOG);
1031 if (err < 0)
1032 goto done;
1033
1034 err = reftable_iterator_seek_log(&it, "");
1035 if (err < 0)
1036 goto done;
1037
1038 while (1) {
1039 err = reftable_iterator_next_log(&it, &log);
1040 if (err > 0) {
1041 err = 0;
1042 break;
1043 }
1044 if (err < 0)
1045 goto done;
1046 if (first == 0 && reftable_log_record_is_deletion(&log)) {
1047 continue;
1048 }
1049
1050 if (config && config->min_update_index > 0 &&
1051 log.update_index < config->min_update_index) {
1052 continue;
1053 }
1054
1055 if (config && config->time > 0 &&
1056 log.value.update.time < config->time) {
1057 continue;
1058 }
1059
1060 err = reftable_writer_add_log(wr, &log);
1061 if (err < 0)
1062 goto done;
1063 entries++;
1064 }
1065
1066 done:
1067 reftable_iterator_destroy(&it);
1068 if (mt)
1069 reftable_merged_table_free(mt);
1070 reftable_ref_record_release(&ref);
1071 reftable_log_record_release(&log);
1072 st->stats.entries_written += entries;
1073 return err;
1074 }
1075
1076 static int stack_compact_locked(struct reftable_stack *st,
1077 size_t first, size_t last,
1078 struct reftable_log_expiry_config *config,
1079 const struct reftable_write_options *opts,
1080 struct reftable_tmpfile *tab_file_out)
1081 {
1082 struct reftable_buf next_name = REFTABLE_BUF_INIT;
1083 struct reftable_buf tab_file_path = REFTABLE_BUF_INIT;
1084 struct reftable_writer *wr = NULL;
1085 struct fd_writer writer= {
1086 .opts = opts,
1087 };
1088 struct reftable_tmpfile tab_file = REFTABLE_TMPFILE_INIT;
1089 int err = 0;
1090
1091 err = format_name(&next_name, reftable_table_min_update_index(st->tables[first]),
1092 reftable_table_max_update_index(st->tables[last]));
1093 if (err < 0)
1094 goto done;
1095
1096 err = stack_filename(&tab_file_path, st, next_name.buf);
1097 if (err < 0)
1098 goto done;
1099
1100 err = reftable_buf_addstr(&tab_file_path, ".temp.XXXXXX");
1101 if (err < 0)
1102 goto done;
1103
1104 err = tmpfile_from_pattern(&tab_file, tab_file_path.buf);
1105 if (err < 0)
1106 goto done;
1107
1108 if (opts->default_permissions &&
1109 chmod(tab_file.path, opts->default_permissions) < 0) {
1110 err = REFTABLE_IO_ERROR;
1111 goto done;
1112 }
1113
1114 writer.fd = tab_file.fd;
1115 err = reftable_writer_new(&wr, fd_writer_write, fd_writer_flush,
1116 &writer, st->opts.hash_id, opts);
1117 if (err < 0)
1118 goto done;
1119
1120 err = stack_write_compact(st, wr, first, last, config);
1121 if (err < 0)
1122 goto done;
1123
1124 err = reftable_writer_close(wr);
1125 if (err < 0)
1126 goto done;
1127
1128 err = tmpfile_close(&tab_file);
1129 if (err < 0)
1130 goto done;
1131
1132 *tab_file_out = tab_file;
1133 tab_file = REFTABLE_TMPFILE_INIT;
1134
1135 done:
1136 tmpfile_delete(&tab_file);
1137 reftable_writer_free(wr);
1138 reftable_buf_release(&next_name);
1139 reftable_buf_release(&tab_file_path);
1140 return err;
1141 }
1142
1143 enum stack_compact_range_flags {
1144 /*
1145 * Perform a best-effort compaction. That is, even if we cannot lock
1146 * all tables in the specified range, we will try to compact the
1147 * remaining slice.
1148 */
1149 STACK_COMPACT_RANGE_BEST_EFFORT = (1 << 0),
1150 };
1151
1152 /*
1153 * Compact all tables in the range `[first, last)` into a single new table.
1154 *
1155 * This function returns `0` on success or a code `< 0` on failure. When the
1156 * stack or any of the tables in the specified range are already locked then
1157 * this function returns `REFTABLE_LOCK_ERROR`. This is a benign error that
1158 * callers can either ignore, or they may choose to retry compaction after some
1159 * amount of time.
1160 */
1161 static int stack_compact_range(struct reftable_stack *st,
1162 size_t first, size_t last,
1163 struct reftable_log_expiry_config *expiry,
1164 const struct reftable_write_options *opts,
1165 unsigned int flags)
1166 {
1167 struct reftable_buf tables_list_buf = REFTABLE_BUF_INIT;
1168 struct reftable_buf new_table_name = REFTABLE_BUF_INIT;
1169 struct reftable_buf new_table_path = REFTABLE_BUF_INIT;
1170 struct reftable_buf table_name = REFTABLE_BUF_INIT;
1171 struct reftable_flock tables_list_lock = REFTABLE_FLOCK_INIT;
1172 struct reftable_flock *table_locks = NULL;
1173 struct reftable_tmpfile new_table = REFTABLE_TMPFILE_INIT;
1174 int is_empty_table = 0, err = 0;
1175 size_t first_to_replace, last_to_replace;
1176 size_t i, nlocks = 0;
1177 char **names = NULL;
1178
1179 if (first > last || (!expiry && first == last)) {
1180 err = 0;
1181 goto done;
1182 }
1183
1184 st->stats.attempts++;
1185
1186 /*
1187 * Hold the lock so that we can read "tables.list" and lock all tables
1188 * which are part of the user-specified range.
1189 */
1190 err = flock_acquire(&tables_list_lock, st->list_file, opts->lock_timeout_ms);
1191 if (err < 0)
1192 goto done;
1193
1194 /*
1195 * Check whether the stack is up-to-date. We unfortunately cannot
1196 * handle the situation gracefully in case it's _not_ up-to-date
1197 * because the range of tables that the user has requested us to
1198 * compact may have been changed. So instead we abort.
1199 *
1200 * We could in theory improve the situation by having the caller not
1201 * pass in a range, but instead the list of tables to compact. If so,
1202 * we could check that relevant tables still exist. But for now it's
1203 * good enough to just abort.
1204 */
1205 err = stack_uptodate(st);
1206 if (err < 0)
1207 goto done;
1208 if (err > 0) {
1209 err = REFTABLE_OUTDATED_ERROR;
1210 goto done;
1211 }
1212
1213 /*
1214 * Lock all tables in the user-provided range. This is the slice of our
1215 * stack which we'll compact.
1216 *
1217 * Note that we lock tables in reverse order from last to first. The
1218 * intent behind this is to allow a newer process to perform best
1219 * effort compaction of tables that it has added in the case where an
1220 * older process is still busy compacting tables which are preexisting
1221 * from the point of view of the newer process.
1222 */
1223 REFTABLE_ALLOC_ARRAY(table_locks, last - first + 1);
1224 if (!table_locks) {
1225 err = REFTABLE_OUT_OF_MEMORY_ERROR;
1226 goto done;
1227 }
1228 for (i = 0; i < last - first + 1; i++)
1229 table_locks[i] = REFTABLE_FLOCK_INIT;
1230
1231 for (i = last + 1; i > first; i--) {
1232 err = stack_filename(&table_name, st, reftable_table_name(st->tables[i - 1]));
1233 if (err < 0)
1234 goto done;
1235
1236 err = flock_acquire(&table_locks[nlocks], table_name.buf, 0);
1237 if (err < 0) {
1238 /*
1239 * When the table is locked already we may do a
1240 * best-effort compaction and compact only the tables
1241 * that we have managed to lock so far. This of course
1242 * requires that we have been able to lock at least two
1243 * tables, otherwise there would be nothing to compact.
1244 * In that case, we return a lock error to our caller.
1245 */
1246 if (err == REFTABLE_LOCK_ERROR && last - (i - 1) >= 2 &&
1247 flags & STACK_COMPACT_RANGE_BEST_EFFORT) {
1248 err = 0;
1249 /*
1250 * The subtraction is to offset the index, the
1251 * addition is to only compact up to the table
1252 * of the preceding iteration. They obviously
1253 * cancel each other out, but that may be
1254 * non-obvious when it was omitted.
1255 */
1256 first = (i - 1) + 1;
1257 break;
1258 }
1259
1260 goto done;
1261 }
1262
1263 /*
1264 * We need to close the lockfiles as we might otherwise easily
1265 * run into file descriptor exhaustion when we compress a lot
1266 * of tables.
1267 */
1268 err = flock_close(&table_locks[nlocks++]);
1269 if (err < 0)
1270 goto done;
1271 }
1272
1273 /*
1274 * We have locked all tables in our range and can thus release the
1275 * "tables.list" lock while compacting the locked tables. This allows
1276 * concurrent updates to the stack to proceed.
1277 */
1278 err = flock_release(&tables_list_lock);
1279 if (err < 0) {
1280 err = REFTABLE_IO_ERROR;
1281 goto done;
1282 }
1283
1284 /*
1285 * Compact the now-locked tables into a new table. Note that compacting
1286 * these tables may end up with an empty new table in case tombstones
1287 * end up cancelling out all refs in that range.
1288 */
1289 err = stack_compact_locked(st, first, last, expiry, opts, &new_table);
1290 if (err < 0) {
1291 if (err != REFTABLE_EMPTY_TABLE_ERROR)
1292 goto done;
1293 is_empty_table = 1;
1294 }
1295
1296 /*
1297 * Now that we have written the new, compacted table we need to re-lock
1298 * "tables.list". We'll then replace the compacted range of tables with
1299 * the new table.
1300 */
1301 err = flock_acquire(&tables_list_lock, st->list_file, opts->lock_timeout_ms);
1302 if (err < 0)
1303 goto done;
1304
1305 if (opts->default_permissions) {
1306 if (chmod(tables_list_lock.path,
1307 opts->default_permissions) < 0) {
1308 err = REFTABLE_IO_ERROR;
1309 goto done;
1310 }
1311 }
1312
1313 /*
1314 * As we have unlocked the stack while compacting our slice of tables
1315 * it may have happened that a concurrently running process has updated
1316 * the stack while we were compacting. In that case, we need to check
1317 * whether the tables that we have just compacted still exist in the
1318 * stack in the exact same order as we have compacted them.
1319 *
1320 * If they do exist, then it is fine to continue and replace those
1321 * tables with our compacted version. If they don't, then we need to
1322 * abort.
1323 */
1324 err = stack_uptodate(st);
1325 if (err < 0)
1326 goto done;
1327 if (err > 0) {
1328 ssize_t new_offset = -1;
1329 int fd;
1330
1331 fd = open(st->list_file, O_RDONLY);
1332 if (fd < 0) {
1333 err = REFTABLE_IO_ERROR;
1334 goto done;
1335 }
1336
1337 err = fd_read_lines(fd, &names);
1338 close(fd);
1339 if (err < 0)
1340 goto done;
1341
1342 /*
1343 * Search for the offset of the first table that we have
1344 * compacted in the updated "tables.list" file.
1345 */
1346 for (size_t i = 0; names[i]; i++) {
1347 if (strcmp(names[i], st->tables[first]->name))
1348 continue;
1349
1350 /*
1351 * We have found the first entry. Verify that all the
1352 * subsequent tables we have compacted still exist in
1353 * the modified stack in the exact same order as we
1354 * have compacted them.
1355 */
1356 for (size_t j = 1; j < last - first + 1; j++) {
1357 const char *old = first + j < st->merged->tables_len ?
1358 st->tables[first + j]->name : NULL;
1359 const char *new = names[i + j];
1360
1361 /*
1362 * If some entries are missing or in case the tables
1363 * have changed then we need to bail out. Again, this
1364 * shouldn't ever happen because we have locked the
1365 * tables we are compacting.
1366 */
1367 if (!old || !new || strcmp(old, new)) {
1368 err = REFTABLE_OUTDATED_ERROR;
1369 goto done;
1370 }
1371 }
1372
1373 new_offset = i;
1374 break;
1375 }
1376
1377 /*
1378 * In case we didn't find our compacted tables in the stack we
1379 * need to bail out. In theory, this should have never happened
1380 * because we locked the tables we are compacting.
1381 */
1382 if (new_offset < 0) {
1383 err = REFTABLE_OUTDATED_ERROR;
1384 goto done;
1385 }
1386
1387 /*
1388 * We have found the new range that we want to replace, so
1389 * let's update the range of tables that we want to replace.
1390 */
1391 first_to_replace = new_offset;
1392 last_to_replace = last + (new_offset - first);
1393 } else {
1394 /*
1395 * `fd_read_lines()` uses a `NULL` sentinel to indicate that
1396 * the array is at its end. As we use `free_names()` to free
1397 * the array, we need to include this sentinel value here and
1398 * thus have to allocate `tables_len + 1` many entries.
1399 */
1400 REFTABLE_CALLOC_ARRAY(names, st->merged->tables_len + 1);
1401 if (!names) {
1402 err = REFTABLE_OUT_OF_MEMORY_ERROR;
1403 goto done;
1404 }
1405
1406 for (size_t i = 0; i < st->merged->tables_len; i++) {
1407 names[i] = reftable_strdup(st->tables[i]->name);
1408 if (!names[i]) {
1409 err = REFTABLE_OUT_OF_MEMORY_ERROR;
1410 goto done;
1411 }
1412 }
1413 first_to_replace = first;
1414 last_to_replace = last;
1415 }
1416
1417 /*
1418 * If the resulting compacted table is not empty, then we need to move
1419 * it into place now.
1420 */
1421 if (!is_empty_table) {
1422 err = format_name(&new_table_name, st->tables[first]->min_update_index,
1423 st->tables[last]->max_update_index);
1424 if (err < 0)
1425 goto done;
1426
1427 err = reftable_buf_addstr(&new_table_name, ".ref");
1428 if (err < 0)
1429 goto done;
1430
1431 err = stack_filename(&new_table_path, st, new_table_name.buf);
1432 if (err < 0)
1433 goto done;
1434
1435 err = tmpfile_rename(&new_table, new_table_path.buf);
1436 if (err < 0)
1437 goto done;
1438 }
1439
1440 /*
1441 * Write the new "tables.list" contents with the compacted table we
1442 * have just written. In case the compacted table became empty we
1443 * simply skip writing it.
1444 */
1445 for (i = 0; i < first_to_replace; i++) {
1446 if ((err = reftable_buf_addstr(&tables_list_buf, names[i])) < 0 ||
1447 (err = reftable_buf_addstr(&tables_list_buf, "\n")) < 0)
1448 goto done;
1449 }
1450 if (!is_empty_table) {
1451 if ((err = reftable_buf_addstr(&tables_list_buf, new_table_name.buf)) < 0 ||
1452 (err = reftable_buf_addstr(&tables_list_buf, "\n")) < 0)
1453 goto done;
1454 }
1455 for (i = last_to_replace + 1; names[i]; i++) {
1456 if ((err = reftable_buf_addstr(&tables_list_buf, names[i])) < 0 ||
1457 (err = reftable_buf_addstr(&tables_list_buf, "\n")) < 0)
1458 goto done;
1459 }
1460
1461 err = reftable_write_data(tables_list_lock.fd,
1462 tables_list_buf.buf, tables_list_buf.len);
1463 if (err < 0) {
1464 err = REFTABLE_IO_ERROR;
1465 unlink(new_table_path.buf);
1466 goto done;
1467 }
1468
1469 err = fsync(tables_list_lock.fd);
1470 if (err < 0) {
1471 err = REFTABLE_IO_ERROR;
1472 unlink(new_table_path.buf);
1473 goto done;
1474 }
1475
1476 err = flock_commit(&tables_list_lock);
1477 if (err < 0) {
1478 err = REFTABLE_IO_ERROR;
1479 unlink(new_table_path.buf);
1480 goto done;
1481 }
1482
1483 /*
1484 * Reload the stack before deleting the compacted tables. We can only
1485 * delete the files after we closed them on Windows, so this needs to
1486 * happen first.
1487 */
1488 err = reftable_stack_reload_maybe_reuse(st, first < last);
1489 if (err < 0)
1490 goto done;
1491
1492 /*
1493 * Delete the old tables. They may still be in use by concurrent
1494 * readers, so it is expected that unlinking tables may fail.
1495 */
1496 for (i = 0; i < nlocks; i++) {
1497 struct reftable_flock *table_lock = &table_locks[i];
1498
1499 reftable_buf_reset(&table_name);
1500 err = reftable_buf_add(&table_name, table_lock->path,
1501 strlen(table_lock->path) - strlen(".lock"));
1502 if (err)
1503 continue;
1504
1505 unlink(table_name.buf);
1506 }
1507
1508 done:
1509 flock_release(&tables_list_lock);
1510 for (i = 0; table_locks && i < nlocks; i++)
1511 flock_release(&table_locks[i]);
1512 reftable_free(table_locks);
1513
1514 tmpfile_delete(&new_table);
1515 reftable_buf_release(&new_table_name);
1516 reftable_buf_release(&new_table_path);
1517 reftable_buf_release(&tables_list_buf);
1518 reftable_buf_release(&table_name);
1519 free_names(names);
1520
1521 if (err == REFTABLE_LOCK_ERROR)
1522 st->stats.failures++;
1523
1524 return err;
1525 }
1526
1527 int reftable_stack_compact_all(struct reftable_stack *st,
1528 const struct reftable_write_options *opts,
1529 struct reftable_log_expiry_config *config)
1530 {
1531 struct reftable_write_options opts_default = { 0 };
1532 size_t last = st->merged->tables_len ? st->merged->tables_len - 1 : 0;
1533
1534 if (!opts)
1535 opts = &opts_default;
1536
1537 return stack_compact_range(st, 0, last, config, opts, 0);
1538 }
1539
1540 static int segment_size(struct segment *s)
1541 {
1542 return s->end - s->start;
1543 }
1544
1545 struct segment suggest_compaction_segment(uint64_t *sizes, size_t n,
1546 uint8_t factor)
1547 {
1548 struct segment seg = { 0 };
1549 uint64_t bytes;
1550 size_t i;
1551
1552 if (!factor)
1553 factor = DEFAULT_GEOMETRIC_FACTOR;
1554
1555 /*
1556 * If there are no tables or only a single one then we don't have to
1557 * compact anything. The sequence is geometric by definition already.
1558 */
1559 if (n <= 1)
1560 return seg;
1561
1562 /*
1563 * Find the ending table of the compaction segment needed to restore the
1564 * geometric sequence. Note that the segment end is exclusive.
1565 *
1566 * To do so, we iterate backwards starting from the most recent table
1567 * until a valid segment end is found. If the preceding table is smaller
1568 * than the current table multiplied by the geometric factor (2), the
1569 * compaction segment end has been identified.
1570 *
1571 * Tables after the ending point are not added to the byte count because
1572 * they are already valid members of the geometric sequence. Due to the
1573 * properties of a geometric sequence, it is not possible for the sum of
1574 * these tables to exceed the value of the ending point table.
1575 *
1576 * Example table size sequence requiring no compaction:
1577 * 64, 32, 16, 8, 4, 2, 1
1578 *
1579 * Example table size sequence where compaction segment end is set to
1580 * the last table. Since the segment end is exclusive, the last table is
1581 * excluded during subsequent compaction and the table with size 3 is
1582 * the final table included:
1583 * 64, 32, 16, 8, 4, 3, 1
1584 */
1585 for (i = n - 1; i > 0; i--) {
1586 if (sizes[i - 1] < sizes[i] * factor) {
1587 seg.end = i + 1;
1588 bytes = sizes[i];
1589 break;
1590 }
1591 }
1592
1593 /*
1594 * Find the starting table of the compaction segment by iterating
1595 * through the remaining tables and keeping track of the accumulated
1596 * size of all tables seen from the segment end table. The previous
1597 * table is compared to the accumulated size because the tables from the
1598 * segment end are merged backwards recursively.
1599 *
1600 * Note that we keep iterating even after we have found the first
1601 * starting point. This is because there may be tables in the stack
1602 * preceding that first starting point which violate the geometric
1603 * sequence.
1604 *
1605 * Example compaction segment start set to table with size 32:
1606 * 128, 32, 16, 8, 4, 3, 1
1607 */
1608 for (; i > 0; i--) {
1609 uint64_t curr = bytes;
1610 bytes += sizes[i - 1];
1611
1612 if (sizes[i - 1] < curr * factor) {
1613 seg.start = i - 1;
1614 seg.bytes = bytes;
1615 }
1616 }
1617
1618 return seg;
1619 }
1620
1621 static int stack_segments_for_compaction(struct reftable_stack *st,
1622 const struct reftable_write_options *opts,
1623 struct segment *seg)
1624 {
1625 int version = (st->opts.hash_id == REFTABLE_HASH_SHA1) ? 1 : 2;
1626 int overhead = header_size(version) - 1;
1627 uint64_t *sizes;
1628
1629 REFTABLE_CALLOC_ARRAY(sizes, st->merged->tables_len);
1630 if (!sizes)
1631 return REFTABLE_OUT_OF_MEMORY_ERROR;
1632
1633 for (size_t i = 0; i < st->merged->tables_len; i++)
1634 sizes[i] = st->tables[i]->size - overhead;
1635
1636 *seg = suggest_compaction_segment(sizes, st->merged->tables_len,
1637 opts->auto_compaction_factor);
1638 reftable_free(sizes);
1639
1640 return 0;
1641 }
1642
1643 static int update_segment_if_compaction_required(struct reftable_stack *st,
1644 const struct reftable_write_options *opts,
1645 struct segment *seg,
1646 bool use_geometric,
1647 bool *required)
1648 {
1649 int err;
1650
1651 if (st->merged->tables_len < 2) {
1652 *required = false;
1653 return 0;
1654 }
1655
1656 if (!use_geometric) {
1657 *required = true;
1658 return 0;
1659 }
1660
1661 err = stack_segments_for_compaction(st, opts, seg);
1662 if (err)
1663 return err;
1664
1665 *required = segment_size(seg) > 0;
1666 return 0;
1667 }
1668
1669 int reftable_stack_compaction_required(struct reftable_stack *st,
1670 const struct reftable_write_options *opts,
1671 bool use_heuristics,
1672 bool *required)
1673 {
1674 struct reftable_write_options opts_default = { 0 };
1675 struct segment seg;
1676
1677 if (!opts)
1678 opts = &opts_default;
1679
1680 return update_segment_if_compaction_required(st, opts, &seg,
1681 use_heuristics, required);
1682 }
1683
1684 int reftable_stack_auto_compact(struct reftable_stack *st,
1685 const struct reftable_write_options *opts)
1686 {
1687 struct reftable_write_options opts_default = { 0 };
1688 struct segment seg;
1689 bool required;
1690 int err;
1691
1692 if (!opts)
1693 opts = &opts_default;
1694
1695 err = update_segment_if_compaction_required(st, opts, &seg, true,
1696 &required);
1697 if (err)
1698 return err;
1699
1700 if (required)
1701 return stack_compact_range(st, seg.start, seg.end - 1,
1702 NULL, opts,
1703 STACK_COMPACT_RANGE_BEST_EFFORT);
1704
1705 return 0;
1706 }
1707
1708 struct reftable_compaction_stats *
1709 reftable_stack_compaction_stats(struct reftable_stack *st)
1710 {
1711 return &st->stats;
1712 }
1713
1714 int reftable_stack_read_ref(struct reftable_stack *st, const char *refname,
1715 struct reftable_ref_record *ref)
1716 {
1717 struct reftable_iterator it = { 0 };
1718 int ret;
1719
1720 ret = reftable_merged_table_init_ref_iterator(st->merged, &it);
1721 if (ret)
1722 goto out;
1723
1724 ret = reftable_iterator_seek_ref(&it, refname);
1725 if (ret)
1726 goto out;
1727
1728 ret = reftable_iterator_next_ref(&it, ref);
1729 if (ret)
1730 goto out;
1731
1732 if (strcmp(ref->refname, refname) ||
1733 reftable_ref_record_is_deletion(ref)) {
1734 reftable_ref_record_release(ref);
1735 ret = 1;
1736 goto out;
1737 }
1738
1739 out:
1740 reftable_iterator_destroy(&it);
1741 return ret;
1742 }
1743
1744 int reftable_stack_read_log(struct reftable_stack *st, const char *refname,
1745 struct reftable_log_record *log)
1746 {
1747 struct reftable_iterator it = {0};
1748 int err;
1749
1750 err = reftable_stack_init_log_iterator(st, &it);
1751 if (err)
1752 goto done;
1753
1754 err = reftable_iterator_seek_log(&it, refname);
1755 if (err)
1756 goto done;
1757
1758 err = reftable_iterator_next_log(&it, log);
1759 if (err)
1760 goto done;
1761
1762 if (strcmp(log->refname, refname) ||
1763 reftable_log_record_is_deletion(log)) {
1764 err = 1;
1765 goto done;
1766 }
1767
1768 done:
1769 if (err) {
1770 reftable_log_record_release(log);
1771 }
1772 reftable_iterator_destroy(&it);
1773 return err;
1774 }
1775
1776 static int is_table_name(const char *s)
1777 {
1778 const char *dot = strrchr(s, '.');
1779 return dot && !strcmp(dot, ".ref");
1780 }
1781
1782 static void remove_maybe_stale_table(struct reftable_stack *st, uint64_t max,
1783 const char *name)
1784 {
1785 int err = 0;
1786 uint64_t update_idx = 0;
1787 struct reftable_block_source src = { NULL };
1788 struct reftable_table *table = NULL;
1789 struct reftable_buf table_path = REFTABLE_BUF_INIT;
1790
1791 err = stack_filename(&table_path, st, name);
1792 if (err < 0)
1793 goto done;
1794
1795 err = reftable_block_source_from_file(&src, table_path.buf);
1796 if (err < 0)
1797 goto done;
1798
1799 err = reftable_table_new(&table, &src, name);
1800 if (err < 0)
1801 goto done;
1802
1803 update_idx = reftable_table_max_update_index(table);
1804 reftable_table_decref(table);
1805
1806 if (update_idx <= max) {
1807 unlink(table_path.buf);
1808 }
1809 done:
1810 reftable_buf_release(&table_path);
1811 }
1812
1813 static int reftable_stack_clean_locked(struct reftable_stack *st)
1814 {
1815 uint64_t max = reftable_merged_table_max_update_index(
1816 reftable_stack_merged_table(st));
1817 DIR *dir = opendir(st->reftable_dir);
1818 struct dirent *d = NULL;
1819 if (!dir) {
1820 return REFTABLE_IO_ERROR;
1821 }
1822
1823 while ((d = readdir(dir))) {
1824 int found = 0;
1825 if (!is_table_name(d->d_name))
1826 continue;
1827
1828 for (size_t i = 0; !found && i < st->tables_len; i++)
1829 found = !strcmp(reftable_table_name(st->tables[i]), d->d_name);
1830 if (found)
1831 continue;
1832
1833 remove_maybe_stale_table(st, max, d->d_name);
1834 }
1835
1836 closedir(dir);
1837 return 0;
1838 }
1839
1840 int reftable_stack_clean(struct reftable_stack *st)
1841 {
1842 struct reftable_addition *add = NULL;
1843 int err = reftable_stack_new_addition(&add, st, NULL, 0);
1844 if (err < 0) {
1845 goto done;
1846 }
1847
1848 err = reftable_stack_reload(st);
1849 if (err < 0) {
1850 goto done;
1851 }
1852
1853 err = reftable_stack_clean_locked(st);
1854
1855 done:
1856 reftable_addition_destroy(add);
1857 return err;
1858 }
1859
1860 enum reftable_hash reftable_stack_hash_id(struct reftable_stack *st)
1861 {
1862 return reftable_merged_table_hash_id(st->merged);
1863 }