Coverage Report

Created: 2026-06-10 06:21

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