2 Copyright 2020 Google LLC
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
15 #include "reftable-error.h"
16 #include "reftable-record.h"
17 #include "reftable-merged.h"
20 static int stack_try_add(struct reftable_stack
*st
,
21 int (*write_table
)(struct reftable_writer
*wr
,
24 static int stack_write_compact(struct reftable_stack
*st
,
25 struct reftable_writer
*wr
, int first
, int last
,
26 struct reftable_log_expiry_config
*config
);
27 static int stack_check_addition(struct reftable_stack
*st
,
28 const char *new_tab_name
);
29 static void reftable_addition_close(struct reftable_addition
*add
);
30 static int reftable_stack_reload_maybe_reuse(struct reftable_stack
*st
,
33 static void stack_filename(struct strbuf
*dest
, struct reftable_stack
*st
,
37 strbuf_addstr(dest
, st
->reftable_dir
);
38 strbuf_addstr(dest
, "/");
39 strbuf_addstr(dest
, name
);
42 static ssize_t
reftable_fd_write(void *arg
, const void *data
, size_t sz
)
44 int *fdp
= (int *)arg
;
45 return write(*fdp
, data
, sz
);
48 int reftable_new_stack(struct reftable_stack
**dest
, const char *dir
,
49 struct reftable_write_options config
)
51 struct reftable_stack
*p
=
52 reftable_calloc(sizeof(struct reftable_stack
));
53 struct strbuf list_file_name
= STRBUF_INIT
;
56 if (config
.hash_id
== 0) {
57 config
.hash_id
= GIT_SHA1_FORMAT_ID
;
62 strbuf_reset(&list_file_name
);
63 strbuf_addstr(&list_file_name
, dir
);
64 strbuf_addstr(&list_file_name
, "/tables.list");
66 p
->list_file
= strbuf_detach(&list_file_name
, NULL
);
67 p
->reftable_dir
= xstrdup(dir
);
70 err
= reftable_stack_reload_maybe_reuse(p
, 1);
72 reftable_stack_destroy(p
);
79 static int fd_read_lines(int fd
, char ***namesp
)
81 off_t size
= lseek(fd
, 0, SEEK_END
);
85 err
= REFTABLE_IO_ERROR
;
88 err
= lseek(fd
, 0, SEEK_SET
);
90 err
= REFTABLE_IO_ERROR
;
94 buf
= reftable_malloc(size
+ 1);
95 if (read(fd
, buf
, size
) != size
) {
96 err
= REFTABLE_IO_ERROR
;
101 parse_names(buf
, size
, namesp
);
108 int read_lines(const char *filename
, char ***namesp
)
110 int fd
= open(filename
, O_RDONLY
);
113 if (errno
== ENOENT
) {
114 *namesp
= reftable_calloc(sizeof(char *));
118 return REFTABLE_IO_ERROR
;
120 err
= fd_read_lines(fd
, namesp
);
125 struct reftable_merged_table
*
126 reftable_stack_merged_table(struct reftable_stack
*st
)
131 static int has_name(char **names
, const char *name
)
134 if (!strcmp(*names
, name
))
141 /* Close and free the stack */
142 void reftable_stack_destroy(struct reftable_stack
*st
)
147 reftable_merged_table_free(st
->merged
);
151 err
= read_lines(st
->list_file
, &names
);
153 FREE_AND_NULL(names
);
158 struct strbuf filename
= STRBUF_INIT
;
159 for (i
= 0; i
< st
->readers_len
; i
++) {
160 const char *name
= reader_name(st
->readers
[i
]);
161 strbuf_reset(&filename
);
162 if (names
&& !has_name(names
, name
)) {
163 stack_filename(&filename
, st
, name
);
165 reftable_reader_free(st
->readers
[i
]);
168 /* On Windows, can only unlink after closing. */
169 unlink(filename
.buf
);
172 strbuf_release(&filename
);
174 FREE_AND_NULL(st
->readers
);
176 FREE_AND_NULL(st
->list_file
);
177 FREE_AND_NULL(st
->reftable_dir
);
182 static struct reftable_reader
**stack_copy_readers(struct reftable_stack
*st
,
185 struct reftable_reader
**cur
=
186 reftable_calloc(sizeof(struct reftable_reader
*) * cur_len
);
188 for (i
= 0; i
< cur_len
; i
++) {
189 cur
[i
] = st
->readers
[i
];
194 static int reftable_stack_reload_once(struct reftable_stack
*st
, char **names
,
197 int cur_len
= !st
->merged
? 0 : st
->merged
->stack_len
;
198 struct reftable_reader
**cur
= stack_copy_readers(st
, cur_len
);
200 int names_len
= names_length(names
);
201 struct reftable_reader
**new_readers
=
202 reftable_calloc(sizeof(struct reftable_reader
*) * names_len
);
203 struct reftable_table
*new_tables
=
204 reftable_calloc(sizeof(struct reftable_table
) * names_len
);
205 int new_readers_len
= 0;
206 struct reftable_merged_table
*new_merged
= NULL
;
210 struct reftable_reader
*rd
= NULL
;
211 char *name
= *names
++;
213 /* this is linear; we assume compaction keeps the number of
214 tables under control so this is not quadratic. */
216 for (j
= 0; reuse_open
&& j
< cur_len
; j
++) {
217 if (cur
[j
] && 0 == strcmp(cur
[j
]->name
, name
)) {
225 struct reftable_block_source src
= { NULL
};
226 struct strbuf table_path
= STRBUF_INIT
;
227 stack_filename(&table_path
, st
, name
);
229 err
= reftable_block_source_from_file(&src
,
231 strbuf_release(&table_path
);
236 err
= reftable_new_reader(&rd
, &src
, name
);
241 new_readers
[new_readers_len
] = rd
;
242 reftable_table_from_reader(&new_tables
[new_readers_len
], rd
);
247 err
= reftable_new_merged_table(&new_merged
, new_tables
,
248 new_readers_len
, st
->config
.hash_id
);
253 st
->readers_len
= new_readers_len
;
255 merged_table_release(st
->merged
);
256 reftable_merged_table_free(st
->merged
);
259 reftable_free(st
->readers
);
261 st
->readers
= new_readers
;
265 new_merged
->suppress_deletions
= 1;
266 st
->merged
= new_merged
;
267 for (i
= 0; i
< cur_len
; i
++) {
269 const char *name
= reader_name(cur
[i
]);
270 struct strbuf filename
= STRBUF_INIT
;
271 stack_filename(&filename
, st
, name
);
273 reader_close(cur
[i
]);
274 reftable_reader_free(cur
[i
]);
276 /* On Windows, can only unlink after closing. */
277 unlink(filename
.buf
);
279 strbuf_release(&filename
);
284 for (i
= 0; i
< new_readers_len
; i
++) {
285 reader_close(new_readers
[i
]);
286 reftable_reader_free(new_readers
[i
]);
288 reftable_free(new_readers
);
289 reftable_free(new_tables
);
294 /* return negative if a before b. */
295 static int tv_cmp(struct timeval
*a
, struct timeval
*b
)
297 time_t diff
= a
->tv_sec
- b
->tv_sec
;
298 int udiff
= a
->tv_usec
- b
->tv_usec
;
306 static int reftable_stack_reload_maybe_reuse(struct reftable_stack
*st
,
309 struct timeval deadline
= { 0 };
310 int err
= gettimeofday(&deadline
, NULL
);
316 deadline
.tv_sec
+= 3;
319 char **names_after
= NULL
;
320 struct timeval now
= { 0 };
321 int err
= gettimeofday(&now
, NULL
);
327 /* Only look at deadlines after the first few times. This
328 simplifies debugging in GDB */
330 if (tries
> 3 && tv_cmp(&now
, &deadline
) >= 0) {
334 err
= read_lines(st
->list_file
, &names
);
339 err
= reftable_stack_reload_once(st
, names
, reuse_open
);
344 if (err
!= REFTABLE_NOT_EXIST_ERROR
) {
349 /* err == REFTABLE_NOT_EXIST_ERROR can be caused by a concurrent
350 writer. Check if there was one by checking if the name list
353 err2
= read_lines(st
->list_file
, &names_after
);
359 if (names_equal(names_after
, names
)) {
361 free_names(names_after
);
365 free_names(names_after
);
367 delay
= delay
+ (delay
* rand()) / RAND_MAX
+ 1;
368 sleep_millisec(delay
);
377 static int stack_uptodate(struct reftable_stack
*st
)
380 int err
= read_lines(st
->list_file
, &names
);
385 for (i
= 0; i
< st
->readers_len
; i
++) {
391 if (strcmp(st
->readers
[i
]->name
, names
[i
])) {
397 if (names
[st
->merged
->stack_len
]) {
407 int reftable_stack_reload(struct reftable_stack
*st
)
409 int err
= stack_uptodate(st
);
411 return reftable_stack_reload_maybe_reuse(st
, 1);
415 int reftable_stack_add(struct reftable_stack
*st
,
416 int (*write
)(struct reftable_writer
*wr
, void *arg
),
419 int err
= stack_try_add(st
, write
, arg
);
421 if (err
== REFTABLE_LOCK_ERROR
) {
422 /* Ignore error return, we want to propagate
425 reftable_stack_reload(st
);
430 if (!st
->disable_auto_compact
)
431 return reftable_stack_auto_compact(st
);
436 static void format_name(struct strbuf
*dest
, uint64_t min
, uint64_t max
)
439 uint32_t rnd
= (uint32_t)rand();
440 snprintf(buf
, sizeof(buf
), "0x%012" PRIx64
"-0x%012" PRIx64
"-%08x",
443 strbuf_addstr(dest
, buf
);
446 struct reftable_addition
{
448 struct strbuf lock_file_name
;
449 struct reftable_stack
*stack
;
453 uint64_t next_update_index
;
456 #define REFTABLE_ADDITION_INIT \
458 .lock_file_name = STRBUF_INIT \
461 static int reftable_stack_init_addition(struct reftable_addition
*add
,
462 struct reftable_stack
*st
)
467 strbuf_reset(&add
->lock_file_name
);
468 strbuf_addstr(&add
->lock_file_name
, st
->list_file
);
469 strbuf_addstr(&add
->lock_file_name
, ".lock");
471 add
->lock_file_fd
= open(add
->lock_file_name
.buf
,
472 O_EXCL
| O_CREAT
| O_WRONLY
, 0666);
473 if (add
->lock_file_fd
< 0) {
474 if (errno
== EEXIST
) {
475 err
= REFTABLE_LOCK_ERROR
;
477 err
= REFTABLE_IO_ERROR
;
481 if (st
->config
.default_permissions
) {
482 if (chmod(add
->lock_file_name
.buf
, st
->config
.default_permissions
) < 0) {
483 err
= REFTABLE_IO_ERROR
;
488 err
= stack_uptodate(st
);
493 err
= REFTABLE_LOCK_ERROR
;
497 add
->next_update_index
= reftable_stack_next_update_index(st
);
500 reftable_addition_close(add
);
505 static void reftable_addition_close(struct reftable_addition
*add
)
508 struct strbuf nm
= STRBUF_INIT
;
509 for (i
= 0; i
< add
->new_tables_len
; i
++) {
510 stack_filename(&nm
, add
->stack
, add
->new_tables
[i
]);
512 reftable_free(add
->new_tables
[i
]);
513 add
->new_tables
[i
] = NULL
;
515 reftable_free(add
->new_tables
);
516 add
->new_tables
= NULL
;
517 add
->new_tables_len
= 0;
519 if (add
->lock_file_fd
> 0) {
520 close(add
->lock_file_fd
);
521 add
->lock_file_fd
= 0;
523 if (add
->lock_file_name
.len
> 0) {
524 unlink(add
->lock_file_name
.buf
);
525 strbuf_release(&add
->lock_file_name
);
531 void reftable_addition_destroy(struct reftable_addition
*add
)
536 reftable_addition_close(add
);
540 int reftable_addition_commit(struct reftable_addition
*add
)
542 struct strbuf table_list
= STRBUF_INIT
;
545 if (add
->new_tables_len
== 0)
548 for (i
= 0; i
< add
->stack
->merged
->stack_len
; i
++) {
549 strbuf_addstr(&table_list
, add
->stack
->readers
[i
]->name
);
550 strbuf_addstr(&table_list
, "\n");
552 for (i
= 0; i
< add
->new_tables_len
; i
++) {
553 strbuf_addstr(&table_list
, add
->new_tables
[i
]);
554 strbuf_addstr(&table_list
, "\n");
557 err
= write(add
->lock_file_fd
, table_list
.buf
, table_list
.len
);
558 strbuf_release(&table_list
);
560 err
= REFTABLE_IO_ERROR
;
564 err
= close(add
->lock_file_fd
);
565 add
->lock_file_fd
= 0;
567 err
= REFTABLE_IO_ERROR
;
571 err
= rename(add
->lock_file_name
.buf
, add
->stack
->list_file
);
573 err
= REFTABLE_IO_ERROR
;
577 /* success, no more state to clean up. */
578 strbuf_release(&add
->lock_file_name
);
579 for (i
= 0; i
< add
->new_tables_len
; i
++) {
580 reftable_free(add
->new_tables
[i
]);
582 reftable_free(add
->new_tables
);
583 add
->new_tables
= NULL
;
584 add
->new_tables_len
= 0;
586 err
= reftable_stack_reload(add
->stack
);
588 reftable_addition_close(add
);
592 int reftable_stack_new_addition(struct reftable_addition
**dest
,
593 struct reftable_stack
*st
)
596 struct reftable_addition empty
= REFTABLE_ADDITION_INIT
;
597 *dest
= reftable_calloc(sizeof(**dest
));
599 err
= reftable_stack_init_addition(*dest
, st
);
601 reftable_free(*dest
);
607 static int stack_try_add(struct reftable_stack
*st
,
608 int (*write_table
)(struct reftable_writer
*wr
,
612 struct reftable_addition add
= REFTABLE_ADDITION_INIT
;
613 int err
= reftable_stack_init_addition(&add
, st
);
617 err
= REFTABLE_LOCK_ERROR
;
621 err
= reftable_addition_add(&add
, write_table
, arg
);
625 err
= reftable_addition_commit(&add
);
627 reftable_addition_close(&add
);
631 int reftable_addition_add(struct reftable_addition
*add
,
632 int (*write_table
)(struct reftable_writer
*wr
,
636 struct strbuf temp_tab_file_name
= STRBUF_INIT
;
637 struct strbuf tab_file_name
= STRBUF_INIT
;
638 struct strbuf next_name
= STRBUF_INIT
;
639 struct reftable_writer
*wr
= NULL
;
643 strbuf_reset(&next_name
);
644 format_name(&next_name
, add
->next_update_index
, add
->next_update_index
);
646 stack_filename(&temp_tab_file_name
, add
->stack
, next_name
.buf
);
647 strbuf_addstr(&temp_tab_file_name
, ".temp.XXXXXX");
649 tab_fd
= mkstemp(temp_tab_file_name
.buf
);
651 err
= REFTABLE_IO_ERROR
;
654 if (add
->stack
->config
.default_permissions
) {
655 if (chmod(temp_tab_file_name
.buf
, add
->stack
->config
.default_permissions
)) {
656 err
= REFTABLE_IO_ERROR
;
660 wr
= reftable_new_writer(reftable_fd_write
, &tab_fd
,
661 &add
->stack
->config
);
662 err
= write_table(wr
, arg
);
666 err
= reftable_writer_close(wr
);
667 if (err
== REFTABLE_EMPTY_TABLE_ERROR
) {
677 err
= REFTABLE_IO_ERROR
;
681 err
= stack_check_addition(add
->stack
, temp_tab_file_name
.buf
);
685 if (wr
->min_update_index
< add
->next_update_index
) {
686 err
= REFTABLE_API_ERROR
;
690 format_name(&next_name
, wr
->min_update_index
, wr
->max_update_index
);
691 strbuf_addstr(&next_name
, ".ref");
693 stack_filename(&tab_file_name
, add
->stack
, next_name
.buf
);
696 On windows, this relies on rand() picking a unique destination name.
697 Maybe we should do retry loop as well?
699 err
= rename(temp_tab_file_name
.buf
, tab_file_name
.buf
);
701 err
= REFTABLE_IO_ERROR
;
705 add
->new_tables
= reftable_realloc(add
->new_tables
,
706 sizeof(*add
->new_tables
) *
707 (add
->new_tables_len
+ 1));
708 add
->new_tables
[add
->new_tables_len
] = strbuf_detach(&next_name
, NULL
);
709 add
->new_tables_len
++;
715 if (temp_tab_file_name
.len
> 0) {
716 unlink(temp_tab_file_name
.buf
);
719 strbuf_release(&temp_tab_file_name
);
720 strbuf_release(&tab_file_name
);
721 strbuf_release(&next_name
);
722 reftable_writer_free(wr
);
726 uint64_t reftable_stack_next_update_index(struct reftable_stack
*st
)
728 int sz
= st
->merged
->stack_len
;
730 return reftable_reader_max_update_index(st
->readers
[sz
- 1]) +
735 static int stack_compact_locked(struct reftable_stack
*st
, int first
, int last
,
736 struct strbuf
*temp_tab
,
737 struct reftable_log_expiry_config
*config
)
739 struct strbuf next_name
= STRBUF_INIT
;
741 struct reftable_writer
*wr
= NULL
;
744 format_name(&next_name
,
745 reftable_reader_min_update_index(st
->readers
[first
]),
746 reftable_reader_max_update_index(st
->readers
[last
]));
748 stack_filename(temp_tab
, st
, next_name
.buf
);
749 strbuf_addstr(temp_tab
, ".temp.XXXXXX");
751 tab_fd
= mkstemp(temp_tab
->buf
);
752 wr
= reftable_new_writer(reftable_fd_write
, &tab_fd
, &st
->config
);
754 err
= stack_write_compact(st
, wr
, first
, last
, config
);
757 err
= reftable_writer_close(wr
);
765 reftable_writer_free(wr
);
770 if (err
!= 0 && temp_tab
->len
> 0) {
771 unlink(temp_tab
->buf
);
772 strbuf_release(temp_tab
);
774 strbuf_release(&next_name
);
778 static int stack_write_compact(struct reftable_stack
*st
,
779 struct reftable_writer
*wr
, int first
, int last
,
780 struct reftable_log_expiry_config
*config
)
782 int subtabs_len
= last
- first
+ 1;
783 struct reftable_table
*subtabs
= reftable_calloc(
784 sizeof(struct reftable_table
) * (last
- first
+ 1));
785 struct reftable_merged_table
*mt
= NULL
;
787 struct reftable_iterator it
= { NULL
};
788 struct reftable_ref_record ref
= { NULL
};
789 struct reftable_log_record log
= { NULL
};
791 uint64_t entries
= 0;
794 for (i
= first
, j
= 0; i
<= last
; i
++) {
795 struct reftable_reader
*t
= st
->readers
[i
];
796 reftable_table_from_reader(&subtabs
[j
++], t
);
797 st
->stats
.bytes
+= t
->size
;
799 reftable_writer_set_limits(wr
, st
->readers
[first
]->min_update_index
,
800 st
->readers
[last
]->max_update_index
);
802 err
= reftable_new_merged_table(&mt
, subtabs
, subtabs_len
,
805 reftable_free(subtabs
);
809 err
= reftable_merged_table_seek_ref(mt
, &it
, "");
814 err
= reftable_iterator_next_ref(&it
, &ref
);
823 if (first
== 0 && reftable_ref_record_is_deletion(&ref
)) {
827 err
= reftable_writer_add_ref(wr
, &ref
);
833 reftable_iterator_destroy(&it
);
835 err
= reftable_merged_table_seek_log(mt
, &it
, "");
840 err
= reftable_iterator_next_log(&it
, &log
);
848 if (first
== 0 && reftable_log_record_is_deletion(&log
)) {
852 if (config
&& config
->min_update_index
> 0 &&
853 log
.update_index
< config
->min_update_index
) {
857 if (config
&& config
->time
> 0 &&
858 log
.value
.update
.time
< config
->time
) {
862 err
= reftable_writer_add_log(wr
, &log
);
870 reftable_iterator_destroy(&it
);
872 merged_table_release(mt
);
873 reftable_merged_table_free(mt
);
875 reftable_ref_record_release(&ref
);
876 reftable_log_record_release(&log
);
877 st
->stats
.entries_written
+= entries
;
881 /* < 0: error. 0 == OK, > 0 attempt failed; could retry. */
882 static int stack_compact_range(struct reftable_stack
*st
, int first
, int last
,
883 struct reftable_log_expiry_config
*expiry
)
885 struct strbuf temp_tab_file_name
= STRBUF_INIT
;
886 struct strbuf new_table_name
= STRBUF_INIT
;
887 struct strbuf lock_file_name
= STRBUF_INIT
;
888 struct strbuf ref_list_contents
= STRBUF_INIT
;
889 struct strbuf new_table_path
= STRBUF_INIT
;
892 int lock_file_fd
= -1;
893 int compact_count
= last
- first
+ 1;
895 char **delete_on_success
=
896 reftable_calloc(sizeof(char *) * (compact_count
+ 1));
897 char **subtable_locks
=
898 reftable_calloc(sizeof(char *) * (compact_count
+ 1));
901 int is_empty_table
= 0;
903 if (first
> last
|| (!expiry
&& first
== last
)) {
908 st
->stats
.attempts
++;
910 strbuf_reset(&lock_file_name
);
911 strbuf_addstr(&lock_file_name
, st
->list_file
);
912 strbuf_addstr(&lock_file_name
, ".lock");
915 open(lock_file_name
.buf
, O_EXCL
| O_CREAT
| O_WRONLY
, 0666);
916 if (lock_file_fd
< 0) {
917 if (errno
== EEXIST
) {
920 err
= REFTABLE_IO_ERROR
;
924 /* Don't want to write to the lock for now. */
929 err
= stack_uptodate(st
);
933 for (i
= first
, j
= 0; i
<= last
; i
++) {
934 struct strbuf subtab_file_name
= STRBUF_INIT
;
935 struct strbuf subtab_lock
= STRBUF_INIT
;
936 int sublock_file_fd
= -1;
938 stack_filename(&subtab_file_name
, st
,
939 reader_name(st
->readers
[i
]));
941 strbuf_reset(&subtab_lock
);
942 strbuf_addbuf(&subtab_lock
, &subtab_file_name
);
943 strbuf_addstr(&subtab_lock
, ".lock");
945 sublock_file_fd
= open(subtab_lock
.buf
,
946 O_EXCL
| O_CREAT
| O_WRONLY
, 0666);
947 if (sublock_file_fd
>= 0) {
948 close(sublock_file_fd
);
949 } else if (sublock_file_fd
< 0) {
950 if (errno
== EEXIST
) {
953 err
= REFTABLE_IO_ERROR
;
957 subtable_locks
[j
] = subtab_lock
.buf
;
958 delete_on_success
[j
] = subtab_file_name
.buf
;
965 err
= unlink(lock_file_name
.buf
);
970 err
= stack_compact_locked(st
, first
, last
, &temp_tab_file_name
,
972 /* Compaction + tombstones can create an empty table out of non-empty
974 is_empty_table
= (err
== REFTABLE_EMPTY_TABLE_ERROR
);
975 if (is_empty_table
) {
982 open(lock_file_name
.buf
, O_EXCL
| O_CREAT
| O_WRONLY
, 0666);
983 if (lock_file_fd
< 0) {
984 if (errno
== EEXIST
) {
987 err
= REFTABLE_IO_ERROR
;
992 if (st
->config
.default_permissions
) {
993 if (chmod(lock_file_name
.buf
, st
->config
.default_permissions
) < 0) {
994 err
= REFTABLE_IO_ERROR
;
999 format_name(&new_table_name
, st
->readers
[first
]->min_update_index
,
1000 st
->readers
[last
]->max_update_index
);
1001 strbuf_addstr(&new_table_name
, ".ref");
1003 stack_filename(&new_table_path
, st
, new_table_name
.buf
);
1005 if (!is_empty_table
) {
1007 err
= rename(temp_tab_file_name
.buf
, new_table_path
.buf
);
1009 err
= REFTABLE_IO_ERROR
;
1014 for (i
= 0; i
< first
; i
++) {
1015 strbuf_addstr(&ref_list_contents
, st
->readers
[i
]->name
);
1016 strbuf_addstr(&ref_list_contents
, "\n");
1018 if (!is_empty_table
) {
1019 strbuf_addbuf(&ref_list_contents
, &new_table_name
);
1020 strbuf_addstr(&ref_list_contents
, "\n");
1022 for (i
= last
+ 1; i
< st
->merged
->stack_len
; i
++) {
1023 strbuf_addstr(&ref_list_contents
, st
->readers
[i
]->name
);
1024 strbuf_addstr(&ref_list_contents
, "\n");
1027 err
= write(lock_file_fd
, ref_list_contents
.buf
, ref_list_contents
.len
);
1029 err
= REFTABLE_IO_ERROR
;
1030 unlink(new_table_path
.buf
);
1033 err
= close(lock_file_fd
);
1036 err
= REFTABLE_IO_ERROR
;
1037 unlink(new_table_path
.buf
);
1041 err
= rename(lock_file_name
.buf
, st
->list_file
);
1043 err
= REFTABLE_IO_ERROR
;
1044 unlink(new_table_path
.buf
);
1049 /* Reload the stack before deleting. On windows, we can only delete the
1050 files after we closed them.
1052 err
= reftable_stack_reload_maybe_reuse(st
, first
< last
);
1054 listp
= delete_on_success
;
1056 if (strcmp(*listp
, new_table_path
.buf
)) {
1063 free_names(delete_on_success
);
1065 listp
= subtable_locks
;
1070 free_names(subtable_locks
);
1071 if (lock_file_fd
>= 0) {
1072 close(lock_file_fd
);
1076 unlink(lock_file_name
.buf
);
1078 strbuf_release(&new_table_name
);
1079 strbuf_release(&new_table_path
);
1080 strbuf_release(&ref_list_contents
);
1081 strbuf_release(&temp_tab_file_name
);
1082 strbuf_release(&lock_file_name
);
1086 int reftable_stack_compact_all(struct reftable_stack
*st
,
1087 struct reftable_log_expiry_config
*config
)
1089 return stack_compact_range(st
, 0, st
->merged
->stack_len
- 1, config
);
1092 static int stack_compact_range_stats(struct reftable_stack
*st
, int first
,
1094 struct reftable_log_expiry_config
*config
)
1096 int err
= stack_compact_range(st
, first
, last
, config
);
1098 st
->stats
.failures
++;
1103 static int segment_size(struct segment
*s
)
1105 return s
->end
- s
->start
;
1108 int fastlog2(uint64_t sz
)
1113 for (; sz
; sz
/= 2) {
1119 struct segment
*sizes_to_segments(int *seglen
, uint64_t *sizes
, int n
)
1121 struct segment
*segs
= reftable_calloc(sizeof(struct segment
) * n
);
1123 struct segment cur
= { 0 };
1130 for (i
= 0; i
< n
; i
++) {
1131 int log
= fastlog2(sizes
[i
]);
1132 if (cur
.log
!= log
&& cur
.bytes
> 0) {
1133 struct segment fresh
= {
1143 cur
.bytes
+= sizes
[i
];
1150 struct segment
suggest_compaction_segment(uint64_t *sizes
, int n
)
1153 struct segment
*segs
= sizes_to_segments(&seglen
, sizes
, n
);
1154 struct segment min_seg
= {
1158 for (i
= 0; i
< seglen
; i
++) {
1159 if (segment_size(&segs
[i
]) == 1) {
1163 if (segs
[i
].log
< min_seg
.log
) {
1168 while (min_seg
.start
> 0) {
1169 int prev
= min_seg
.start
- 1;
1170 if (fastlog2(min_seg
.bytes
) < fastlog2(sizes
[prev
])) {
1174 min_seg
.start
= prev
;
1175 min_seg
.bytes
+= sizes
[prev
];
1178 reftable_free(segs
);
1182 static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack
*st
)
1185 reftable_calloc(sizeof(uint64_t) * st
->merged
->stack_len
);
1186 int version
= (st
->config
.hash_id
== GIT_SHA1_FORMAT_ID
) ? 1 : 2;
1187 int overhead
= header_size(version
) - 1;
1189 for (i
= 0; i
< st
->merged
->stack_len
; i
++) {
1190 sizes
[i
] = st
->readers
[i
]->size
- overhead
;
1195 int reftable_stack_auto_compact(struct reftable_stack
*st
)
1197 uint64_t *sizes
= stack_table_sizes_for_compaction(st
);
1198 struct segment seg
=
1199 suggest_compaction_segment(sizes
, st
->merged
->stack_len
);
1200 reftable_free(sizes
);
1201 if (segment_size(&seg
) > 0)
1202 return stack_compact_range_stats(st
, seg
.start
, seg
.end
- 1,
1208 struct reftable_compaction_stats
*
1209 reftable_stack_compaction_stats(struct reftable_stack
*st
)
1214 int reftable_stack_read_ref(struct reftable_stack
*st
, const char *refname
,
1215 struct reftable_ref_record
*ref
)
1217 struct reftable_table tab
= { NULL
};
1218 reftable_table_from_merged_table(&tab
, reftable_stack_merged_table(st
));
1219 return reftable_table_read_ref(&tab
, refname
, ref
);
1222 int reftable_stack_read_log(struct reftable_stack
*st
, const char *refname
,
1223 struct reftable_log_record
*log
)
1225 struct reftable_iterator it
= { NULL
};
1226 struct reftable_merged_table
*mt
= reftable_stack_merged_table(st
);
1227 int err
= reftable_merged_table_seek_log(mt
, &it
, refname
);
1231 err
= reftable_iterator_next_log(&it
, log
);
1235 if (strcmp(log
->refname
, refname
) ||
1236 reftable_log_record_is_deletion(log
)) {
1243 reftable_log_record_release(log
);
1245 reftable_iterator_destroy(&it
);
1249 static int stack_check_addition(struct reftable_stack
*st
,
1250 const char *new_tab_name
)
1253 struct reftable_block_source src
= { NULL
};
1254 struct reftable_reader
*rd
= NULL
;
1255 struct reftable_table tab
= { NULL
};
1256 struct reftable_ref_record
*refs
= NULL
;
1257 struct reftable_iterator it
= { NULL
};
1262 if (st
->config
.skip_name_check
)
1265 err
= reftable_block_source_from_file(&src
, new_tab_name
);
1269 err
= reftable_new_reader(&rd
, &src
, new_tab_name
);
1273 err
= reftable_reader_seek_ref(rd
, &it
, "");
1282 struct reftable_ref_record ref
= { NULL
};
1283 err
= reftable_iterator_next_ref(&it
, &ref
);
1292 refs
= reftable_realloc(refs
, cap
* sizeof(refs
[0]));
1298 reftable_table_from_merged_table(&tab
, reftable_stack_merged_table(st
));
1300 err
= validate_ref_record_addition(tab
, refs
, len
);
1303 for (i
= 0; i
< len
; i
++) {
1304 reftable_ref_record_release(&refs
[i
]);
1308 reftable_iterator_destroy(&it
);
1309 reftable_reader_free(rd
);
1313 static int is_table_name(const char *s
)
1315 const char *dot
= strrchr(s
, '.');
1316 return dot
&& !strcmp(dot
, ".ref");
1319 static void remove_maybe_stale_table(struct reftable_stack
*st
, uint64_t max
,
1323 uint64_t update_idx
= 0;
1324 struct reftable_block_source src
= { NULL
};
1325 struct reftable_reader
*rd
= NULL
;
1326 struct strbuf table_path
= STRBUF_INIT
;
1327 stack_filename(&table_path
, st
, name
);
1329 err
= reftable_block_source_from_file(&src
, table_path
.buf
);
1333 err
= reftable_new_reader(&rd
, &src
, name
);
1337 update_idx
= reftable_reader_max_update_index(rd
);
1338 reftable_reader_free(rd
);
1340 if (update_idx
<= max
) {
1341 unlink(table_path
.buf
);
1344 strbuf_release(&table_path
);
1347 static int reftable_stack_clean_locked(struct reftable_stack
*st
)
1349 uint64_t max
= reftable_merged_table_max_update_index(
1350 reftable_stack_merged_table(st
));
1351 DIR *dir
= opendir(st
->reftable_dir
);
1352 struct dirent
*d
= NULL
;
1354 return REFTABLE_IO_ERROR
;
1357 while ((d
= readdir(dir
))) {
1360 if (!is_table_name(d
->d_name
))
1363 for (i
= 0; !found
&& i
< st
->readers_len
; i
++) {
1364 found
= !strcmp(reader_name(st
->readers
[i
]), d
->d_name
);
1369 remove_maybe_stale_table(st
, max
, d
->d_name
);
1376 int reftable_stack_clean(struct reftable_stack
*st
)
1378 struct reftable_addition
*add
= NULL
;
1379 int err
= reftable_stack_new_addition(&add
, st
);
1384 err
= reftable_stack_reload(st
);
1389 err
= reftable_stack_clean_locked(st
);
1392 reftable_addition_destroy(add
);
1396 int reftable_stack_print_directory(const char *stackdir
, uint32_t hash_id
)
1398 struct reftable_stack
*stack
= NULL
;
1399 struct reftable_write_options cfg
= { .hash_id
= hash_id
};
1400 struct reftable_merged_table
*merged
= NULL
;
1401 struct reftable_table table
= { NULL
};
1403 int err
= reftable_new_stack(&stack
, stackdir
, cfg
);
1407 merged
= reftable_stack_merged_table(stack
);
1408 reftable_table_from_merged_table(&table
, merged
);
1409 err
= reftable_table_print(&table
);
1412 reftable_stack_destroy(stack
);