Coverage Report

Created: 2026-08-13 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libgit2/deps/reftable/stack.c
Line
Count
Source
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
0
{
23
0
  int err;
24
0
  reftable_buf_reset(dest);
25
0
  if ((err = reftable_buf_addstr(dest, st->reftable_dir)) < 0 ||
26
0
      (err = reftable_buf_addstr(dest, "/")) < 0 ||
27
0
      (err = reftable_buf_addstr(dest, name)) < 0)
28
0
    return err;
29
0
  return 0;
30
0
}
31
32
static ssize_t reftable_write_data(int fd, const void *data, size_t size)
33
0
{
34
0
  size_t total_written = 0;
35
0
  const char *p = data;
36
37
0
  while (total_written < size) {
38
0
    ssize_t bytes_written = write(fd, p, size - total_written);
39
0
    if (bytes_written < 0 && (errno == EAGAIN || errno == EINTR))
40
0
      continue;
41
0
    if (bytes_written < 0)
42
0
      return REFTABLE_IO_ERROR;
43
44
0
    total_written += bytes_written;
45
0
    p += bytes_written;
46
0
  }
47
48
0
  return total_written;
49
0
}
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
0
{
58
0
  struct fd_writer *writer = arg;
59
0
  return reftable_write_data(writer->fd, data, sz);
60
0
}
61
62
static int fd_writer_flush(void *arg)
63
0
{
64
0
  struct fd_writer *writer = arg;
65
0
  return fsync(writer->fd);
66
0
}
67
68
static int fd_read_lines(int fd, char ***namesp)
69
0
{
70
0
  char *buf = NULL;
71
0
  int err = 0;
72
0
  off_t size;
73
74
0
  size = lseek(fd, 0, SEEK_END);
75
0
  if (size < 0) {
76
0
    err = REFTABLE_IO_ERROR;
77
0
    goto done;
78
0
  }
79
80
0
  err = lseek(fd, 0, SEEK_SET);
81
0
  if (err < 0) {
82
0
    err = REFTABLE_IO_ERROR;
83
0
    goto done;
84
0
  }
85
86
0
  REFTABLE_ALLOC_ARRAY(buf, size + 1);
87
0
  if (!buf) {
88
0
    err = REFTABLE_OUT_OF_MEMORY_ERROR;
89
0
    goto done;
90
0
  }
91
92
0
  for (off_t total_read = 0; total_read < size; ) {
93
0
    ssize_t bytes_read = read(fd, buf + total_read, size - total_read);
94
0
    if (bytes_read < 0 && (errno == EAGAIN || errno == EINTR))
95
0
      continue;
96
0
    if (bytes_read < 0 || !bytes_read) {
97
0
      err = REFTABLE_IO_ERROR;
98
0
      goto done;
99
0
    }
100
101
0
    total_read += bytes_read;
102
0
  }
103
0
  buf[size] = 0;
104
105
0
  err = parse_names(buf, size, namesp);
106
0
done:
107
0
  reftable_free(buf);
108
0
  return err;
109
0
}
110
111
int read_lines(const char *filename, char ***namesp)
112
0
{
113
0
  int fd = open(filename, O_RDONLY);
114
0
  int err = 0;
115
0
  if (fd < 0) {
116
0
    if (errno == ENOENT) {
117
0
      REFTABLE_CALLOC_ARRAY(*namesp, 1);
118
0
      if (!*namesp)
119
0
        return REFTABLE_OUT_OF_MEMORY_ERROR;
120
0
      return 0;
121
0
    }
122
123
0
    return REFTABLE_IO_ERROR;
124
0
  }
125
0
  err = fd_read_lines(fd, namesp);
126
0
  close(fd);
127
0
  return err;
128
0
}
129
130
int reftable_stack_init_ref_iterator(struct reftable_stack *st,
131
              struct reftable_iterator *it)
132
0
{
133
0
  return merged_table_init_iter(reftable_stack_merged_table(st),
134
0
              it, REFTABLE_BLOCK_TYPE_REF);
135
0
}
136
137
int reftable_stack_init_log_iterator(struct reftable_stack *st,
138
             struct reftable_iterator *it)
139
0
{
140
0
  return merged_table_init_iter(reftable_stack_merged_table(st),
141
0
              it, REFTABLE_BLOCK_TYPE_LOG);
142
0
}
143
144
struct reftable_merged_table *
145
reftable_stack_merged_table(struct reftable_stack *st)
146
0
{
147
0
  return st->merged;
148
0
}
149
150
static int has_name(char **names, const char *name)
151
0
{
152
0
  while (*names) {
153
0
    if (!strcmp(*names, name))
154
0
      return 1;
155
0
    names++;
156
0
  }
157
0
  return 0;
158
0
}
159
160
/* Close and free the stack */
161
void reftable_stack_destroy(struct reftable_stack *st)
162
0
{
163
0
  char **names = NULL;
164
0
  int err = 0;
165
166
0
  if (!st)
167
0
    return;
168
169
0
  if (st->merged) {
170
0
    reftable_merged_table_free(st->merged);
171
0
    st->merged = NULL;
172
0
  }
173
174
0
  if (st->list_file)
175
0
    err = read_lines(st->list_file, &names);
176
0
  if (err < 0) {
177
0
    REFTABLE_FREE_AND_NULL(names);
178
0
  }
179
180
0
  if (st->tables) {
181
0
    struct reftable_buf filename = REFTABLE_BUF_INIT;
182
183
0
    for (size_t i = 0; i < st->tables_len; i++) {
184
0
      const char *name = reftable_table_name(st->tables[i]);
185
0
      int try_unlinking = 1;
186
187
0
      reftable_buf_reset(&filename);
188
0
      if (names && !has_name(names, name)) {
189
0
        if (stack_filename(&filename, st, name) < 0)
190
0
          try_unlinking = 0;
191
0
      }
192
0
      reftable_table_decref(st->tables[i]);
193
194
0
      if (try_unlinking && filename.len) {
195
        /* On Windows, can only unlink after closing. */
196
0
        unlink(filename.buf);
197
0
      }
198
0
    }
199
200
0
    reftable_buf_release(&filename);
201
0
    st->tables_len = 0;
202
0
    REFTABLE_FREE_AND_NULL(st->tables);
203
0
  }
204
205
0
  if (st->list_fd >= 0) {
206
0
    close(st->list_fd);
207
0
    st->list_fd = -1;
208
0
  }
209
210
0
  REFTABLE_FREE_AND_NULL(st->list_file);
211
0
  REFTABLE_FREE_AND_NULL(st->reftable_dir);
212
0
  reftable_free(st);
213
0
  free_names(names);
214
0
}
215
216
static struct reftable_table **stack_copy_tables(struct reftable_stack *st,
217
             size_t cur_len)
218
0
{
219
0
  struct reftable_table **cur = reftable_calloc(cur_len, sizeof(*cur));
220
0
  if (!cur)
221
0
    return NULL;
222
0
  for (size_t i = 0; i < cur_len; i++)
223
0
    cur[i] = st->tables[i];
224
0
  return cur;
225
0
}
226
227
static int reftable_stack_reload_once(struct reftable_stack *st,
228
              const char **names,
229
              int reuse_open)
230
0
{
231
0
  size_t cur_len = !st->merged ? 0 : st->merged->tables_len;
232
0
  struct reftable_table **cur = NULL;
233
0
  struct reftable_table **reused = NULL;
234
0
  struct reftable_table **new_tables = NULL;
235
0
  size_t reused_len = 0, reused_alloc = 0, names_len;
236
0
  size_t new_tables_len = 0;
237
0
  struct reftable_merged_table *new_merged = NULL;
238
0
  struct reftable_buf table_path = REFTABLE_BUF_INIT;
239
0
  int err = 0;
240
0
  size_t i;
241
242
0
  if (cur_len) {
243
0
    cur = stack_copy_tables(st, cur_len);
244
0
    if (!cur) {
245
0
      err = REFTABLE_OUT_OF_MEMORY_ERROR;
246
0
      goto done;
247
0
    }
248
0
  }
249
250
0
  names_len = names_length(names);
251
252
0
  if (names_len) {
253
0
    new_tables = reftable_calloc(names_len, sizeof(*new_tables));
254
0
    if (!new_tables) {
255
0
      err = REFTABLE_OUT_OF_MEMORY_ERROR;
256
0
      goto done;
257
0
    }
258
0
  }
259
260
0
  while (*names) {
261
0
    struct reftable_table *table = NULL;
262
0
    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
0
    for (i = 0; reuse_open && i < cur_len; i++) {
267
0
      if (cur[i] && 0 == strcmp(cur[i]->name, name)) {
268
0
        table = cur[i];
269
0
        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
0
        REFTABLE_ALLOC_GROW_OR_NULL(reused,
280
0
                  reused_len + 1,
281
0
                  reused_alloc);
282
0
        if (!reused) {
283
0
          err = REFTABLE_OUT_OF_MEMORY_ERROR;
284
0
          goto done;
285
0
        }
286
0
        reused[reused_len++] = table;
287
0
        reftable_table_incref(table);
288
0
        break;
289
0
      }
290
0
    }
291
292
0
    if (!table) {
293
0
      struct reftable_block_source src = { NULL };
294
295
0
      err = stack_filename(&table_path, st, name);
296
0
      if (err < 0)
297
0
        goto done;
298
299
0
      err = reftable_block_source_from_file(&src,
300
0
                    table_path.buf);
301
0
      if (err < 0)
302
0
        goto done;
303
304
0
      err = reftable_table_new(&table, &src, name);
305
0
      if (err < 0)
306
0
        goto done;
307
0
    }
308
309
0
    new_tables[new_tables_len] = table;
310
0
    new_tables_len++;
311
0
  }
312
313
  /* success! */
314
0
  err = reftable_merged_table_new(&new_merged, new_tables,
315
0
          new_tables_len, st->opts.hash_id);
316
0
  if (err < 0)
317
0
    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
0
  for (i = 0; i < cur_len; i++) {
326
0
    if (cur[i]) {
327
0
      const char *name = reftable_table_name(cur[i]);
328
329
0
      err = stack_filename(&table_path, st, name);
330
0
      if (err < 0)
331
0
        goto done;
332
333
0
      reftable_table_decref(cur[i]);
334
0
      unlink(table_path.buf);
335
0
    }
336
0
  }
337
338
  /* Update the stack to point to the new tables. */
339
0
  if (st->merged)
340
0
    reftable_merged_table_free(st->merged);
341
0
  new_merged->suppress_deletions = st->opts.suppress_deletions;
342
0
  st->merged = new_merged;
343
344
0
  if (st->tables)
345
0
    reftable_free(st->tables);
346
0
  st->tables = new_tables;
347
0
  st->tables_len = new_tables_len;
348
0
  new_tables = NULL;
349
0
  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
0
  for (i = 0; i < reused_len; i++)
357
0
    reftable_table_decref(reused[i]);
358
359
0
done:
360
0
  for (i = 0; i < new_tables_len; i++)
361
0
    reftable_table_decref(new_tables[i]);
362
0
  reftable_free(new_tables);
363
0
  reftable_free(reused);
364
0
  reftable_free(cur);
365
0
  reftable_buf_release(&table_path);
366
0
  return err;
367
0
}
368
369
static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st,
370
               int reuse_open)
371
0
{
372
0
  char **names = NULL, **names_after = NULL;
373
0
  uint64_t deadline;
374
0
  int64_t delay = 0;
375
0
  int tries = 0, err;
376
0
  int fd = -1;
377
378
0
  deadline = reftable_time_ms() + 3000;
379
380
0
  while (1) {
381
0
    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
0
    tries++;
388
0
    if (tries > 3 && now >= deadline)
389
0
      goto out;
390
391
0
    fd = open(st->list_file, O_RDONLY);
392
0
    if (fd < 0) {
393
0
      if (errno != ENOENT) {
394
0
        err = REFTABLE_IO_ERROR;
395
0
        goto out;
396
0
      }
397
398
0
      REFTABLE_CALLOC_ARRAY(names, 1);
399
0
      if (!names) {
400
0
        err = REFTABLE_OUT_OF_MEMORY_ERROR;
401
0
        goto out;
402
0
      }
403
0
    } else {
404
0
      err = fd_read_lines(fd, &names);
405
0
      if (err < 0)
406
0
        goto out;
407
0
    }
408
409
0
    err = reftable_stack_reload_once(st, (const char **) names, reuse_open);
410
0
    if (!err)
411
0
      break;
412
0
    if (err != REFTABLE_NOT_EXIST_ERROR)
413
0
      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
0
    err = read_lines(st->list_file, &names_after);
421
0
    if (err < 0)
422
0
      goto out;
423
0
    if (names_equal((const char **) names_after,
424
0
        (const char **) names)) {
425
0
      err = REFTABLE_NOT_EXIST_ERROR;
426
0
      goto out;
427
0
    }
428
429
0
    free_names(names);
430
0
    names = NULL;
431
0
    free_names(names_after);
432
0
    names_after = NULL;
433
0
    close(fd);
434
0
    fd = -1;
435
436
0
    delay = delay + (delay * reftable_rand()) / UINT32_MAX + 1;
437
0
    poll(NULL, 0, delay);
438
0
  }
439
440
0
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
0
  if (st->list_fd >= 0) {
447
0
    close(st->list_fd);
448
0
    st->list_fd = -1;
449
0
  }
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
0
  if (!err && fd >= 0 && !fstat(fd, &st->list_st) &&
488
0
      st->list_st.st_dev && st->list_st.st_ino) {
489
0
    st->list_fd = fd;
490
0
    fd = -1;
491
0
  }
492
493
0
  if (fd >= 0)
494
0
    close(fd);
495
0
  free_names(names);
496
0
  free_names(names_after);
497
498
0
  if (st->opts.on_reload)
499
0
    st->opts.on_reload(st->opts.on_reload_payload);
500
501
0
  return err;
502
0
}
503
504
int reftable_new_stack(struct reftable_stack **dest, const char *dir,
505
           const struct reftable_stack_options *_opts)
506
0
{
507
0
  struct reftable_buf list_file_name = REFTABLE_BUF_INIT;
508
0
  struct reftable_stack_options opts = { 0 };
509
0
  struct reftable_stack *p;
510
0
  int err;
511
512
0
  p = reftable_calloc(1, sizeof(*p));
513
0
  if (!p) {
514
0
    err = REFTABLE_OUT_OF_MEMORY_ERROR;
515
0
    goto out;
516
0
  }
517
518
0
  if (_opts)
519
0
    opts = *_opts;
520
0
  if (opts.hash_id == 0)
521
0
    opts.hash_id = REFTABLE_HASH_SHA1;
522
523
0
  *dest = NULL;
524
525
0
  reftable_buf_reset(&list_file_name);
526
0
  if ((err = reftable_buf_addstr(&list_file_name, dir)) < 0 ||
527
0
      (err = reftable_buf_addstr(&list_file_name, "/tables.list")) < 0)
528
0
    goto out;
529
530
0
  p->list_file = reftable_buf_detach(&list_file_name);
531
0
  p->list_fd = -1;
532
0
  p->opts = opts;
533
0
  p->reftable_dir = reftable_strdup(dir);
534
0
  if (!p->reftable_dir) {
535
0
    err = REFTABLE_OUT_OF_MEMORY_ERROR;
536
0
    goto out;
537
0
  }
538
539
0
  err = reftable_stack_reload_maybe_reuse(p, 1);
540
0
  if (err < 0)
541
0
    goto out;
542
543
0
  *dest = p;
544
0
  err = 0;
545
546
0
out:
547
0
  if (err < 0)
548
0
    reftable_stack_destroy(p);
549
0
  return err;
550
0
}
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
0
{
559
0
  char **names = NULL;
560
0
  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
0
  if (st->list_fd >= 0) {
572
0
    struct stat list_st;
573
574
0
    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
0
      if (errno == ENOENT)
581
0
        return !!st->tables_len;
582
0
      return REFTABLE_IO_ERROR;
583
0
    }
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
0
    if (st->list_st.st_dev == list_st.st_dev &&
592
0
        st->list_st.st_ino == list_st.st_ino)
593
0
      return 0;
594
0
  }
595
596
0
  err = read_lines(st->list_file, &names);
597
0
  if (err < 0)
598
0
    return err;
599
600
0
  for (size_t i = 0; i < st->tables_len; i++) {
601
0
    if (!names[i]) {
602
0
      err = 1;
603
0
      goto done;
604
0
    }
605
606
0
    if (strcmp(st->tables[i]->name, names[i])) {
607
0
      err = 1;
608
0
      goto done;
609
0
    }
610
0
  }
611
612
0
  if (names[st->merged->tables_len]) {
613
0
    err = 1;
614
0
    goto done;
615
0
  }
616
617
0
done:
618
0
  free_names(names);
619
0
  return err;
620
0
}
621
622
int reftable_stack_reload(struct reftable_stack *st)
623
0
{
624
0
  int err = stack_uptodate(st);
625
0
  if (err > 0)
626
0
    return reftable_stack_reload_maybe_reuse(st, 1);
627
0
  return err;
628
0
}
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
0
{
642
0
  struct reftable_buf nm = REFTABLE_BUF_INIT;
643
0
  size_t i;
644
645
0
  for (i = 0; i < add->new_tables_len; i++) {
646
0
    if (!stack_filename(&nm, add->stack, add->new_tables[i]))
647
0
      unlink(nm.buf);
648
0
    reftable_free(add->new_tables[i]);
649
0
    add->new_tables[i] = NULL;
650
0
  }
651
0
  reftable_free(add->new_tables);
652
0
  add->new_tables = NULL;
653
0
  add->new_tables_len = 0;
654
0
  add->new_tables_cap = 0;
655
656
0
  flock_release(&add->tables_list_lock);
657
0
  reftable_buf_release(&nm);
658
0
}
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
0
{
665
0
  struct reftable_buf lock_file_name = REFTABLE_BUF_INIT;
666
0
  int err;
667
668
0
  memset(add, 0, sizeof(*add));
669
0
  add->stack = st;
670
0
  if (opts)
671
0
    add->opts = *opts;
672
673
0
  err = flock_acquire(&add->tables_list_lock, st->list_file,
674
0
          add->opts.lock_timeout_ms);
675
0
  if (err < 0)
676
0
    goto done;
677
678
0
  if (add->opts.default_permissions) {
679
0
    if (chmod(add->tables_list_lock.path,
680
0
        add->opts.default_permissions) < 0) {
681
0
      err = REFTABLE_IO_ERROR;
682
0
      goto done;
683
0
    }
684
0
  }
685
686
0
  err = stack_uptodate(st);
687
0
  if (err < 0)
688
0
    goto done;
689
0
  if (err > 0 && flags & REFTABLE_STACK_NEW_ADDITION_RELOAD) {
690
0
    err = reftable_stack_reload_maybe_reuse(add->stack, 1);
691
0
    if (err)
692
0
      goto done;
693
0
  }
694
0
  if (err > 0) {
695
0
    err = REFTABLE_OUTDATED_ERROR;
696
0
    goto done;
697
0
  }
698
699
0
  add->next_update_index = reftable_stack_next_update_index(st);
700
0
done:
701
0
  if (err)
702
0
    reftable_addition_close(add);
703
0
  reftable_buf_release(&lock_file_name);
704
0
  return err;
705
0
}
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
0
{
714
0
  struct reftable_addition add;
715
0
  int err;
716
717
0
  err = reftable_stack_init_addition(&add, st, opts, flags);
718
0
  if (err < 0)
719
0
    goto done;
720
721
0
  err = reftable_addition_add(&add, write_table, arg);
722
0
  if (err < 0)
723
0
    goto done;
724
725
0
  err = reftable_addition_commit(&add);
726
0
done:
727
0
  reftable_addition_close(&add);
728
0
  return err;
729
0
}
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
0
{
737
0
  int err = stack_try_add(st, write, arg, opts, flags);
738
0
  if (err < 0) {
739
0
    if (err == REFTABLE_OUTDATED_ERROR) {
740
      /* Ignore error return, we want to propagate
741
         REFTABLE_OUTDATED_ERROR.
742
      */
743
0
      reftable_stack_reload(st);
744
0
    }
745
0
    return err;
746
0
  }
747
748
0
  return 0;
749
0
}
750
751
static int format_name(struct reftable_buf *dest, uint64_t min, uint64_t max)
752
0
{
753
0
  char buf[100];
754
0
  uint32_t rnd = reftable_rand();
755
0
  snprintf(buf, sizeof(buf), "0x%012" PRIx64 "-0x%012" PRIx64 "-%08x",
756
0
     min, max, rnd);
757
0
  reftable_buf_reset(dest);
758
0
  return reftable_buf_addstr(dest, buf);
759
0
}
760
761
void reftable_addition_destroy(struct reftable_addition *add)
762
0
{
763
0
  if (!add) {
764
0
    return;
765
0
  }
766
0
  reftable_addition_close(add);
767
0
  reftable_free(add);
768
0
}
769
770
int reftable_addition_commit(struct reftable_addition *add)
771
0
{
772
0
  struct reftable_buf table_list = REFTABLE_BUF_INIT;
773
0
  int err = 0;
774
0
  size_t i;
775
776
0
  if (add->new_tables_len == 0)
777
0
    goto done;
778
779
0
  for (i = 0; i < add->stack->merged->tables_len; i++) {
780
0
    if ((err = reftable_buf_addstr(&table_list, add->stack->tables[i]->name)) < 0 ||
781
0
        (err = reftable_buf_addstr(&table_list, "\n")) < 0)
782
0
      goto done;
783
0
  }
784
0
  for (i = 0; i < add->new_tables_len; i++) {
785
0
    if ((err = reftable_buf_addstr(&table_list, add->new_tables[i])) < 0 ||
786
0
        (err = reftable_buf_addstr(&table_list, "\n")) < 0)
787
0
      goto done;
788
0
  }
789
790
0
  err = reftable_write_data(add->tables_list_lock.fd,
791
0
          table_list.buf, table_list.len);
792
0
  reftable_buf_release(&table_list);
793
0
  if (err < 0) {
794
0
    err = REFTABLE_IO_ERROR;
795
0
    goto done;
796
0
  }
797
798
0
  err = fsync(add->tables_list_lock.fd);
799
0
  if (err < 0) {
800
0
    err = REFTABLE_IO_ERROR;
801
0
    goto done;
802
0
  }
803
804
0
  err = flock_commit(&add->tables_list_lock);
805
0
  if (err < 0) {
806
0
    err = REFTABLE_IO_ERROR;
807
0
    goto done;
808
0
  }
809
810
  /* success, no more state to clean up. */
811
0
  for (i = 0; i < add->new_tables_len; i++)
812
0
    reftable_free(add->new_tables[i]);
813
0
  reftable_free(add->new_tables);
814
0
  add->new_tables = NULL;
815
0
  add->new_tables_len = 0;
816
0
  add->new_tables_cap = 0;
817
818
0
  err = reftable_stack_reload_maybe_reuse(add->stack, 1);
819
0
  if (err)
820
0
    goto done;
821
822
0
  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
0
    err = reftable_stack_auto_compact(add->stack, &add->opts);
833
0
    if (err < 0 && err != REFTABLE_LOCK_ERROR &&
834
0
        err != REFTABLE_OUTDATED_ERROR)
835
0
      goto done;
836
0
    err = 0;
837
0
  }
838
839
0
done:
840
0
  reftable_addition_close(add);
841
0
  return err;
842
0
}
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
0
{
849
0
  int err;
850
851
0
  REFTABLE_CALLOC_ARRAY(*dest, 1);
852
0
  if (!*dest)
853
0
    return REFTABLE_OUT_OF_MEMORY_ERROR;
854
855
0
  err = reftable_stack_init_addition(*dest, st, opts, flags);
856
0
  if (err) {
857
0
    reftable_free(*dest);
858
0
    *dest = NULL;
859
0
  }
860
861
0
  return err;
862
0
}
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
0
{
869
0
  struct reftable_buf temp_tab_file_name = REFTABLE_BUF_INIT;
870
0
  struct reftable_buf tab_file_name = REFTABLE_BUF_INIT;
871
0
  struct reftable_buf next_name = REFTABLE_BUF_INIT;
872
0
  struct reftable_writer *wr = NULL;
873
0
  struct reftable_tmpfile tab_file = REFTABLE_TMPFILE_INIT;
874
0
  struct fd_writer writer = {
875
0
    .opts = &add->opts,
876
0
  };
877
0
  int err = 0;
878
879
0
  reftable_buf_reset(&next_name);
880
881
0
  err = format_name(&next_name, add->next_update_index, add->next_update_index);
882
0
  if (err < 0)
883
0
    goto done;
884
885
0
  err = stack_filename(&temp_tab_file_name, add->stack, next_name.buf);
886
0
  if (err < 0)
887
0
    goto done;
888
889
0
  err = reftable_buf_addstr(&temp_tab_file_name, ".temp.XXXXXX");
890
0
  if (err < 0)
891
0
    goto done;
892
893
0
  err = tmpfile_from_pattern(&tab_file, temp_tab_file_name.buf);
894
0
  if (err < 0)
895
0
    goto done;
896
0
  if (add->opts.default_permissions) {
897
0
    if (chmod(tab_file.path,
898
0
        add->opts.default_permissions)) {
899
0
      err = REFTABLE_IO_ERROR;
900
0
      goto done;
901
0
    }
902
0
  }
903
904
0
  writer.fd = tab_file.fd;
905
0
  err = reftable_writer_new(&wr, fd_writer_write, fd_writer_flush,
906
0
          &writer, add->stack->opts.hash_id, &add->opts);
907
0
  if (err < 0)
908
0
    goto done;
909
910
0
  err = write_table(wr, arg);
911
0
  if (err < 0)
912
0
    goto done;
913
914
0
  err = reftable_writer_close(wr);
915
0
  if (err == REFTABLE_EMPTY_TABLE_ERROR) {
916
0
    err = 0;
917
0
    goto done;
918
0
  }
919
0
  if (err < 0)
920
0
    goto done;
921
922
0
  err = tmpfile_close(&tab_file);
923
0
  if (err < 0)
924
0
    goto done;
925
926
0
  if (wr->min_update_index < add->next_update_index) {
927
0
    err = REFTABLE_API_ERROR;
928
0
    goto done;
929
0
  }
930
931
0
  err = format_name(&next_name, wr->min_update_index, wr->max_update_index);
932
0
  if (err < 0)
933
0
    goto done;
934
935
0
  err = reftable_buf_addstr(&next_name, ".ref");
936
0
  if (err < 0)
937
0
    goto done;
938
939
0
  err = stack_filename(&tab_file_name, add->stack, next_name.buf);
940
0
  if (err < 0)
941
0
    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
0
  err = tmpfile_rename(&tab_file, tab_file_name.buf);
948
0
  if (err < 0)
949
0
    goto done;
950
951
0
  REFTABLE_ALLOC_GROW_OR_NULL(add->new_tables, add->new_tables_len + 1,
952
0
            add->new_tables_cap);
953
0
  if (!add->new_tables) {
954
0
    err = REFTABLE_OUT_OF_MEMORY_ERROR;
955
0
    goto done;
956
0
  }
957
0
  add->new_tables[add->new_tables_len++] = reftable_buf_detach(&next_name);
958
959
0
done:
960
0
  tmpfile_delete(&tab_file);
961
0
  reftable_buf_release(&temp_tab_file_name);
962
0
  reftable_buf_release(&tab_file_name);
963
0
  reftable_buf_release(&next_name);
964
0
  reftable_writer_free(wr);
965
0
  return err;
966
0
}
967
968
uint64_t reftable_stack_next_update_index(struct reftable_stack *st)
969
0
{
970
0
  int sz = st->merged->tables_len;
971
0
  if (sz > 0)
972
0
    return reftable_table_max_update_index(st->tables[sz - 1]) +
973
0
           1;
974
0
  return 1;
975
0
}
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
0
{
982
0
  struct reftable_merged_table *mt = NULL;
983
0
  struct reftable_iterator it = { NULL };
984
0
  struct reftable_ref_record ref = { NULL };
985
0
  struct reftable_log_record log = { NULL };
986
0
  size_t subtabs_len = last - first + 1;
987
0
  uint64_t entries = 0;
988
0
  int err = 0;
989
990
0
  for (size_t i = first; i <= last; i++)
991
0
    st->stats.bytes += st->tables[i]->size;
992
0
  err = reftable_writer_set_limits(wr, st->tables[first]->min_update_index,
993
0
           st->tables[last]->max_update_index);
994
0
  if (err < 0)
995
0
    goto done;
996
997
0
  err = reftable_merged_table_new(&mt, st->tables + first, subtabs_len,
998
0
          st->opts.hash_id);
999
0
  if (err < 0)
1000
0
    goto done;
1001
1002
0
  err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_REF);
1003
0
  if (err < 0)
1004
0
    goto done;
1005
1006
0
  err = reftable_iterator_seek_ref(&it, "");
1007
0
  if (err < 0)
1008
0
    goto done;
1009
1010
0
  while (1) {
1011
0
    err = reftable_iterator_next_ref(&it, &ref);
1012
0
    if (err > 0) {
1013
0
      err = 0;
1014
0
      break;
1015
0
    }
1016
0
    if (err < 0)
1017
0
      goto done;
1018
1019
0
    if (first == 0 && reftable_ref_record_is_deletion(&ref)) {
1020
0
      continue;
1021
0
    }
1022
1023
0
    err = reftable_writer_add_ref(wr, &ref);
1024
0
    if (err < 0)
1025
0
      goto done;
1026
0
    entries++;
1027
0
  }
1028
0
  reftable_iterator_destroy(&it);
1029
1030
0
  err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_LOG);
1031
0
  if (err < 0)
1032
0
    goto done;
1033
1034
0
  err = reftable_iterator_seek_log(&it, "");
1035
0
  if (err < 0)
1036
0
    goto done;
1037
1038
0
  while (1) {
1039
0
    err = reftable_iterator_next_log(&it, &log);
1040
0
    if (err > 0) {
1041
0
      err = 0;
1042
0
      break;
1043
0
    }
1044
0
    if (err < 0)
1045
0
      goto done;
1046
0
    if (first == 0 && reftable_log_record_is_deletion(&log)) {
1047
0
      continue;
1048
0
    }
1049
1050
0
    if (config && config->min_update_index > 0 &&
1051
0
        log.update_index < config->min_update_index) {
1052
0
      continue;
1053
0
    }
1054
1055
0
    if (config && config->time > 0 &&
1056
0
        log.value.update.time < config->time) {
1057
0
      continue;
1058
0
    }
1059
1060
0
    err = reftable_writer_add_log(wr, &log);
1061
0
    if (err < 0)
1062
0
      goto done;
1063
0
    entries++;
1064
0
  }
1065
1066
0
done:
1067
0
  reftable_iterator_destroy(&it);
1068
0
  if (mt)
1069
0
    reftable_merged_table_free(mt);
1070
0
  reftable_ref_record_release(&ref);
1071
0
  reftable_log_record_release(&log);
1072
0
  st->stats.entries_written += entries;
1073
0
  return err;
1074
0
}
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
0
{
1082
0
  struct reftable_buf next_name = REFTABLE_BUF_INIT;
1083
0
  struct reftable_buf tab_file_path = REFTABLE_BUF_INIT;
1084
0
  struct reftable_writer *wr = NULL;
1085
0
  struct fd_writer writer=  {
1086
0
    .opts = opts,
1087
0
  };
1088
0
  struct reftable_tmpfile tab_file = REFTABLE_TMPFILE_INIT;
1089
0
  int err = 0;
1090
1091
0
  err = format_name(&next_name, reftable_table_min_update_index(st->tables[first]),
1092
0
        reftable_table_max_update_index(st->tables[last]));
1093
0
  if (err < 0)
1094
0
    goto done;
1095
1096
0
  err = stack_filename(&tab_file_path, st, next_name.buf);
1097
0
  if (err < 0)
1098
0
    goto done;
1099
1100
0
  err = reftable_buf_addstr(&tab_file_path, ".temp.XXXXXX");
1101
0
  if (err < 0)
1102
0
    goto done;
1103
1104
0
  err = tmpfile_from_pattern(&tab_file, tab_file_path.buf);
1105
0
  if (err < 0)
1106
0
    goto done;
1107
1108
0
  if (opts->default_permissions &&
1109
0
      chmod(tab_file.path, opts->default_permissions) < 0) {
1110
0
    err = REFTABLE_IO_ERROR;
1111
0
    goto done;
1112
0
  }
1113
1114
0
  writer.fd = tab_file.fd;
1115
0
  err = reftable_writer_new(&wr, fd_writer_write, fd_writer_flush,
1116
0
          &writer, st->opts.hash_id, opts);
1117
0
  if (err < 0)
1118
0
    goto done;
1119
1120
0
  err = stack_write_compact(st, wr, first, last, config);
1121
0
  if (err < 0)
1122
0
    goto done;
1123
1124
0
  err = reftable_writer_close(wr);
1125
0
  if (err < 0)
1126
0
    goto done;
1127
1128
0
  err = tmpfile_close(&tab_file);
1129
0
  if (err < 0)
1130
0
    goto done;
1131
1132
0
  *tab_file_out = tab_file;
1133
0
  tab_file = REFTABLE_TMPFILE_INIT;
1134
1135
0
done:
1136
0
  tmpfile_delete(&tab_file);
1137
0
  reftable_writer_free(wr);
1138
0
  reftable_buf_release(&next_name);
1139
0
  reftable_buf_release(&tab_file_path);
1140
0
  return err;
1141
0
}
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
0
{
1167
0
  struct reftable_buf tables_list_buf = REFTABLE_BUF_INIT;
1168
0
  struct reftable_buf new_table_name = REFTABLE_BUF_INIT;
1169
0
  struct reftable_buf new_table_path = REFTABLE_BUF_INIT;
1170
0
  struct reftable_buf table_name = REFTABLE_BUF_INIT;
1171
0
  struct reftable_flock tables_list_lock = REFTABLE_FLOCK_INIT;
1172
0
  struct reftable_flock *table_locks = NULL;
1173
0
  struct reftable_tmpfile new_table = REFTABLE_TMPFILE_INIT;
1174
0
  int is_empty_table = 0, err = 0;
1175
0
  size_t first_to_replace, last_to_replace;
1176
0
  size_t i, nlocks = 0;
1177
0
  char **names = NULL;
1178
1179
0
  if (first > last || (!expiry && first == last)) {
1180
0
    err = 0;
1181
0
    goto done;
1182
0
  }
1183
1184
0
  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
0
  err = flock_acquire(&tables_list_lock, st->list_file, opts->lock_timeout_ms);
1191
0
  if (err < 0)
1192
0
    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
0
  err = stack_uptodate(st);
1206
0
  if (err < 0)
1207
0
    goto done;
1208
0
  if (err > 0) {
1209
0
    err = REFTABLE_OUTDATED_ERROR;
1210
0
    goto done;
1211
0
  }
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
0
  REFTABLE_ALLOC_ARRAY(table_locks, last - first + 1);
1224
0
  if (!table_locks) {
1225
0
    err = REFTABLE_OUT_OF_MEMORY_ERROR;
1226
0
    goto done;
1227
0
  }
1228
0
  for (i = 0; i < last - first + 1; i++)
1229
0
    table_locks[i] = REFTABLE_FLOCK_INIT;
1230
1231
0
  for (i = last + 1; i > first; i--) {
1232
0
    err = stack_filename(&table_name, st, reftable_table_name(st->tables[i - 1]));
1233
0
    if (err < 0)
1234
0
      goto done;
1235
1236
0
    err = flock_acquire(&table_locks[nlocks], table_name.buf, 0);
1237
0
    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
0
      if (err == REFTABLE_LOCK_ERROR && last - (i - 1) >= 2 &&
1247
0
          flags & STACK_COMPACT_RANGE_BEST_EFFORT) {
1248
0
        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
0
        first = (i - 1) + 1;
1257
0
        break;
1258
0
      }
1259
1260
0
      goto done;
1261
0
    }
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
0
    err = flock_close(&table_locks[nlocks++]);
1269
0
    if (err < 0)
1270
0
      goto done;
1271
0
  }
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
0
  err = flock_release(&tables_list_lock);
1279
0
  if (err < 0) {
1280
0
    err = REFTABLE_IO_ERROR;
1281
0
    goto done;
1282
0
  }
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
0
  err = stack_compact_locked(st, first, last, expiry, opts, &new_table);
1290
0
  if (err < 0) {
1291
0
    if (err != REFTABLE_EMPTY_TABLE_ERROR)
1292
0
      goto done;
1293
0
    is_empty_table = 1;
1294
0
  }
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
0
  err = flock_acquire(&tables_list_lock, st->list_file, opts->lock_timeout_ms);
1302
0
  if (err < 0)
1303
0
    goto done;
1304
1305
0
  if (opts->default_permissions) {
1306
0
    if (chmod(tables_list_lock.path,
1307
0
        opts->default_permissions) < 0) {
1308
0
      err = REFTABLE_IO_ERROR;
1309
0
      goto done;
1310
0
    }
1311
0
  }
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
0
  err = stack_uptodate(st);
1325
0
  if (err < 0)
1326
0
    goto done;
1327
0
  if (err > 0) {
1328
0
    ssize_t new_offset = -1;
1329
0
    int fd;
1330
1331
0
    fd = open(st->list_file, O_RDONLY);
1332
0
    if (fd < 0) {
1333
0
      err = REFTABLE_IO_ERROR;
1334
0
      goto done;
1335
0
    }
1336
1337
0
    err = fd_read_lines(fd, &names);
1338
0
    close(fd);
1339
0
    if (err < 0)
1340
0
      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
0
    for (size_t i = 0; names[i]; i++) {
1347
0
      if (strcmp(names[i], st->tables[first]->name))
1348
0
        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
0
      for (size_t j = 1; j < last - first + 1; j++) {
1357
0
        const char *old = first + j < st->merged->tables_len ?
1358
0
          st->tables[first + j]->name : NULL;
1359
0
        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
0
        if (!old || !new || strcmp(old, new)) {
1368
0
          err = REFTABLE_OUTDATED_ERROR;
1369
0
          goto done;
1370
0
        }
1371
0
      }
1372
1373
0
      new_offset = i;
1374
0
      break;
1375
0
    }
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
0
    if (new_offset < 0) {
1383
0
      err = REFTABLE_OUTDATED_ERROR;
1384
0
      goto done;
1385
0
    }
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
0
    first_to_replace = new_offset;
1392
0
    last_to_replace = last + (new_offset - first);
1393
0
  } 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
0
    REFTABLE_CALLOC_ARRAY(names, st->merged->tables_len + 1);
1401
0
    if (!names) {
1402
0
      err = REFTABLE_OUT_OF_MEMORY_ERROR;
1403
0
      goto done;
1404
0
    }
1405
1406
0
    for (size_t i = 0; i < st->merged->tables_len; i++) {
1407
0
      names[i] = reftable_strdup(st->tables[i]->name);
1408
0
      if (!names[i]) {
1409
0
        err = REFTABLE_OUT_OF_MEMORY_ERROR;
1410
0
        goto done;
1411
0
      }
1412
0
    }
1413
0
    first_to_replace = first;
1414
0
    last_to_replace = last;
1415
0
  }
1416
1417
  /*
1418
   * If the resulting compacted table is not empty, then we need to move
1419
   * it into place now.
1420
   */
1421
0
  if (!is_empty_table) {
1422
0
    err = format_name(&new_table_name, st->tables[first]->min_update_index,
1423
0
          st->tables[last]->max_update_index);
1424
0
    if (err < 0)
1425
0
      goto done;
1426
1427
0
    err = reftable_buf_addstr(&new_table_name, ".ref");
1428
0
    if (err < 0)
1429
0
      goto done;
1430
1431
0
    err = stack_filename(&new_table_path, st, new_table_name.buf);
1432
0
    if (err < 0)
1433
0
      goto done;
1434
1435
0
    err = tmpfile_rename(&new_table, new_table_path.buf);
1436
0
    if (err < 0)
1437
0
      goto done;
1438
0
  }
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
0
  for (i = 0; i < first_to_replace; i++) {
1446
0
    if ((err = reftable_buf_addstr(&tables_list_buf, names[i])) < 0 ||
1447
0
        (err = reftable_buf_addstr(&tables_list_buf, "\n")) < 0)
1448
0
          goto done;
1449
0
  }
1450
0
  if (!is_empty_table) {
1451
0
    if ((err = reftable_buf_addstr(&tables_list_buf, new_table_name.buf)) < 0 ||
1452
0
        (err = reftable_buf_addstr(&tables_list_buf, "\n")) < 0)
1453
0
      goto done;
1454
0
  }
1455
0
  for (i = last_to_replace + 1; names[i]; i++) {
1456
0
    if ((err = reftable_buf_addstr(&tables_list_buf, names[i])) < 0 ||
1457
0
        (err = reftable_buf_addstr(&tables_list_buf, "\n")) < 0)
1458
0
      goto done;
1459
0
  }
1460
1461
0
  err = reftable_write_data(tables_list_lock.fd,
1462
0
          tables_list_buf.buf, tables_list_buf.len);
1463
0
  if (err < 0) {
1464
0
    err = REFTABLE_IO_ERROR;
1465
0
    unlink(new_table_path.buf);
1466
0
    goto done;
1467
0
  }
1468
1469
0
  err = fsync(tables_list_lock.fd);
1470
0
  if (err < 0) {
1471
0
    err = REFTABLE_IO_ERROR;
1472
0
    unlink(new_table_path.buf);
1473
0
    goto done;
1474
0
  }
1475
1476
0
  err = flock_commit(&tables_list_lock);
1477
0
  if (err < 0) {
1478
0
    err = REFTABLE_IO_ERROR;
1479
0
    unlink(new_table_path.buf);
1480
0
    goto done;
1481
0
  }
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
0
  err = reftable_stack_reload_maybe_reuse(st, first < last);
1489
0
  if (err < 0)
1490
0
    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
0
  for (i = 0; i < nlocks; i++) {
1497
0
    struct reftable_flock *table_lock = &table_locks[i];
1498
1499
0
    reftable_buf_reset(&table_name);
1500
0
    err = reftable_buf_add(&table_name, table_lock->path,
1501
0
               strlen(table_lock->path) - strlen(".lock"));
1502
0
    if (err)
1503
0
      continue;
1504
1505
0
    unlink(table_name.buf);
1506
0
  }
1507
1508
0
done:
1509
0
  flock_release(&tables_list_lock);
1510
0
  for (i = 0; table_locks && i < nlocks; i++)
1511
0
    flock_release(&table_locks[i]);
1512
0
  reftable_free(table_locks);
1513
1514
0
  tmpfile_delete(&new_table);
1515
0
  reftable_buf_release(&new_table_name);
1516
0
  reftable_buf_release(&new_table_path);
1517
0
  reftable_buf_release(&tables_list_buf);
1518
0
  reftable_buf_release(&table_name);
1519
0
  free_names(names);
1520
1521
0
  if (err == REFTABLE_LOCK_ERROR)
1522
0
    st->stats.failures++;
1523
1524
0
  return err;
1525
0
}
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
0
{
1531
0
  struct reftable_write_options opts_default = { 0 };
1532
0
  size_t last = st->merged->tables_len ? st->merged->tables_len - 1 : 0;
1533
1534
0
  if (!opts)
1535
0
    opts = &opts_default;
1536
1537
0
  return stack_compact_range(st, 0, last, config, opts, 0);
1538
0
}
1539
1540
static int segment_size(struct segment *s)
1541
0
{
1542
0
  return s->end - s->start;
1543
0
}
1544
1545
struct segment suggest_compaction_segment(uint64_t *sizes, size_t n,
1546
            uint8_t factor)
1547
0
{
1548
0
  struct segment seg = { 0 };
1549
0
  uint64_t bytes;
1550
0
  size_t i;
1551
1552
0
  if (!factor)
1553
0
    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
0
  if (n <= 1)
1560
0
    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
0
  for (i = n - 1; i > 0; i--) {
1586
0
    if (sizes[i - 1] < sizes[i] * factor) {
1587
0
      seg.end = i + 1;
1588
0
      bytes = sizes[i];
1589
0
      break;
1590
0
    }
1591
0
  }
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
0
  for (; i > 0; i--) {
1609
0
    uint64_t curr = bytes;
1610
0
    bytes += sizes[i - 1];
1611
1612
0
    if (sizes[i - 1] < curr * factor) {
1613
0
      seg.start = i - 1;
1614
0
      seg.bytes = bytes;
1615
0
    }
1616
0
  }
1617
1618
0
  return seg;
1619
0
}
1620
1621
static int stack_segments_for_compaction(struct reftable_stack *st,
1622
           const struct reftable_write_options *opts,
1623
           struct segment *seg)
1624
0
{
1625
0
  int version = (st->opts.hash_id == REFTABLE_HASH_SHA1) ? 1 : 2;
1626
0
  int overhead = header_size(version) - 1;
1627
0
  uint64_t *sizes;
1628
1629
0
  REFTABLE_CALLOC_ARRAY(sizes, st->merged->tables_len);
1630
0
  if (!sizes)
1631
0
    return REFTABLE_OUT_OF_MEMORY_ERROR;
1632
1633
0
  for (size_t i = 0; i < st->merged->tables_len; i++)
1634
0
    sizes[i] = st->tables[i]->size - overhead;
1635
1636
0
  *seg = suggest_compaction_segment(sizes, st->merged->tables_len,
1637
0
            opts->auto_compaction_factor);
1638
0
  reftable_free(sizes);
1639
1640
0
  return 0;
1641
0
}
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
0
{
1649
0
  int err;
1650
1651
0
  if (st->merged->tables_len < 2) {
1652
0
    *required = false;
1653
0
    return 0;
1654
0
  }
1655
1656
0
  if (!use_geometric) {
1657
0
    *required = true;
1658
0
    return 0;
1659
0
  }
1660
1661
0
  err = stack_segments_for_compaction(st, opts, seg);
1662
0
  if (err)
1663
0
    return err;
1664
1665
0
  *required = segment_size(seg) > 0;
1666
0
  return 0;
1667
0
}
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
0
{
1674
0
  struct reftable_write_options opts_default = { 0 };
1675
0
  struct segment seg;
1676
1677
0
  if (!opts)
1678
0
    opts = &opts_default;
1679
1680
0
  return update_segment_if_compaction_required(st, opts, &seg,
1681
0
                 use_heuristics, required);
1682
0
}
1683
1684
int reftable_stack_auto_compact(struct reftable_stack *st,
1685
        const struct reftable_write_options *opts)
1686
0
{
1687
0
  struct reftable_write_options opts_default = { 0 };
1688
0
  struct segment seg;
1689
0
  bool required;
1690
0
  int err;
1691
1692
0
  if (!opts)
1693
0
    opts = &opts_default;
1694
1695
0
  err = update_segment_if_compaction_required(st, opts, &seg, true,
1696
0
                &required);
1697
0
  if (err)
1698
0
    return err;
1699
1700
0
  if (required)
1701
0
    return stack_compact_range(st, seg.start, seg.end - 1,
1702
0
             NULL, opts,
1703
0
             STACK_COMPACT_RANGE_BEST_EFFORT);
1704
1705
0
  return 0;
1706
0
}
1707
1708
struct reftable_compaction_stats *
1709
reftable_stack_compaction_stats(struct reftable_stack *st)
1710
0
{
1711
0
  return &st->stats;
1712
0
}
1713
1714
int reftable_stack_read_ref(struct reftable_stack *st, const char *refname,
1715
          struct reftable_ref_record *ref)
1716
0
{
1717
0
  struct reftable_iterator it = { 0 };
1718
0
  int ret;
1719
1720
0
  ret = reftable_merged_table_init_ref_iterator(st->merged, &it);
1721
0
  if (ret)
1722
0
    goto out;
1723
1724
0
  ret = reftable_iterator_seek_ref(&it, refname);
1725
0
  if (ret)
1726
0
    goto out;
1727
1728
0
  ret = reftable_iterator_next_ref(&it, ref);
1729
0
  if (ret)
1730
0
    goto out;
1731
1732
0
  if (strcmp(ref->refname, refname) ||
1733
0
      reftable_ref_record_is_deletion(ref)) {
1734
0
    reftable_ref_record_release(ref);
1735
0
    ret = 1;
1736
0
    goto out;
1737
0
  }
1738
1739
0
out:
1740
0
  reftable_iterator_destroy(&it);
1741
0
  return ret;
1742
0
}
1743
1744
int reftable_stack_read_log(struct reftable_stack *st, const char *refname,
1745
          struct reftable_log_record *log)
1746
0
{
1747
0
  struct reftable_iterator it = {0};
1748
0
  int err;
1749
1750
0
  err = reftable_stack_init_log_iterator(st, &it);
1751
0
  if (err)
1752
0
    goto done;
1753
1754
0
  err = reftable_iterator_seek_log(&it, refname);
1755
0
  if (err)
1756
0
    goto done;
1757
1758
0
  err = reftable_iterator_next_log(&it, log);
1759
0
  if (err)
1760
0
    goto done;
1761
1762
0
  if (strcmp(log->refname, refname) ||
1763
0
      reftable_log_record_is_deletion(log)) {
1764
0
    err = 1;
1765
0
    goto done;
1766
0
  }
1767
1768
0
done:
1769
0
  if (err) {
1770
0
    reftable_log_record_release(log);
1771
0
  }
1772
0
  reftable_iterator_destroy(&it);
1773
0
  return err;
1774
0
}
1775
1776
static int is_table_name(const char *s)
1777
0
{
1778
0
  const char *dot = strrchr(s, '.');
1779
0
  return dot && !strcmp(dot, ".ref");
1780
0
}
1781
1782
static void remove_maybe_stale_table(struct reftable_stack *st, uint64_t max,
1783
             const char *name)
1784
0
{
1785
0
  int err = 0;
1786
0
  uint64_t update_idx = 0;
1787
0
  struct reftable_block_source src = { NULL };
1788
0
  struct reftable_table *table = NULL;
1789
0
  struct reftable_buf table_path = REFTABLE_BUF_INIT;
1790
1791
0
  err = stack_filename(&table_path, st, name);
1792
0
  if (err < 0)
1793
0
    goto done;
1794
1795
0
  err = reftable_block_source_from_file(&src, table_path.buf);
1796
0
  if (err < 0)
1797
0
    goto done;
1798
1799
0
  err = reftable_table_new(&table, &src, name);
1800
0
  if (err < 0)
1801
0
    goto done;
1802
1803
0
  update_idx = reftable_table_max_update_index(table);
1804
0
  reftable_table_decref(table);
1805
1806
0
  if (update_idx <= max) {
1807
0
    unlink(table_path.buf);
1808
0
  }
1809
0
done:
1810
0
  reftable_buf_release(&table_path);
1811
0
}
1812
1813
static int reftable_stack_clean_locked(struct reftable_stack *st)
1814
0
{
1815
0
  uint64_t max = reftable_merged_table_max_update_index(
1816
0
    reftable_stack_merged_table(st));
1817
0
  DIR *dir = opendir(st->reftable_dir);
1818
0
  struct dirent *d = NULL;
1819
0
  if (!dir) {
1820
0
    return REFTABLE_IO_ERROR;
1821
0
  }
1822
1823
0
  while ((d = readdir(dir))) {
1824
0
    int found = 0;
1825
0
    if (!is_table_name(d->d_name))
1826
0
      continue;
1827
1828
0
    for (size_t i = 0; !found && i < st->tables_len; i++)
1829
0
      found = !strcmp(reftable_table_name(st->tables[i]), d->d_name);
1830
0
    if (found)
1831
0
      continue;
1832
1833
0
    remove_maybe_stale_table(st, max, d->d_name);
1834
0
  }
1835
1836
0
  closedir(dir);
1837
0
  return 0;
1838
0
}
1839
1840
int reftable_stack_clean(struct reftable_stack *st)
1841
0
{
1842
0
  struct reftable_addition *add = NULL;
1843
0
  int err = reftable_stack_new_addition(&add, st, NULL, 0);
1844
0
  if (err < 0) {
1845
0
    goto done;
1846
0
  }
1847
1848
0
  err = reftable_stack_reload(st);
1849
0
  if (err < 0) {
1850
0
    goto done;
1851
0
  }
1852
1853
0
  err = reftable_stack_clean_locked(st);
1854
1855
0
done:
1856
0
  reftable_addition_destroy(add);
1857
0
  return err;
1858
0
}
1859
1860
enum reftable_hash reftable_stack_hash_id(struct reftable_stack *st)
1861
0
{
1862
0
  return reftable_merged_table_hash_id(st->merged);
1863
0
}