From: "Han-Wen Nienhuys via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: "Han-Wen Nienhuys" <hanwen@google.com>,
"Jeff King" <peff@peff.net>,
"Ramsay Jones" <ramsay@ramsayjones.plus.com>,
"Jonathan Nieder" <jrnieder@gmail.com>,
"Johannes Schindelin" <Johannes.Schindelin@gmx.de>,
"Jonathan Tan" <jonathantanmy@google.com>,
"Josh Steadmon" <steadmon@google.com>,
"Emily Shaffer" <emilyshaffer@google.com>,
"Patrick Steinhardt" <ps@pks.im>,
"Ævar Arnfjörð Bjarmason" <avarab@gmail.com>,
"Felipe Contreras" <felipe.contreras@gmail.com>,
"Han-Wen Nienhuys" <hanwenn@gmail.com>
Subject: [PATCH v4 00/15] reftable library
Date: Wed, 09 Dec 2020 14:00:14 +0000 [thread overview]
Message-ID: <pull.847.v4.git.git.1607522429.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.847.v3.git.git.1606419752.gitgitgadget@gmail.com>
This splits the giant commit from
https://github.com/gitgitgadget/git/pull/539 into a series of smaller
commits, which build and have unittests.
The final commit should also be split up, but I want to wait until we have
consensus that the bottom commits look good.
version 8 Dec 2020:
* fixes for windows: add random suffix to table names
* tagged unions for reftable_ref_record
* some fixes by dscho
* some tweaks in response to Felipe Contreras
* switched to github.com/hanwen/reftable (which does not need CLA)
Based on github.com/hanwen/reftable at
c33a40ad23dd622d8c72139c41a2be1cfa063e5f Add random suffix to table names
Han-Wen Nienhuys (14):
init-db: set the_repository->hash_algo early on
reftable: add LICENSE
reftable: add error related functionality
reftable: utility functions
reftable: add blocksource, an abstraction for random access reads
reftable: (de)serialization for the polymorphic record type.
reftable: reading/writing blocks
reftable: a generic binary tree implementation
reftable: write reftable files
reftable: read reftable files
reftable: reftable file level tests
reftable: rest of library
Reftable support for git-core
Add "test-tool dump-reftable" command.
SZEDER Gábor (1):
git-prompt: prepare for reftable refs backend
Documentation/config/extensions.txt | 9 +
.../technical/repository-version.txt | 7 +
Makefile | 46 +-
builtin/clone.c | 5 +-
builtin/init-db.c | 76 +-
builtin/worktree.c | 27 +-
cache.h | 8 +-
config.mak.uname | 2 +-
contrib/buildsystems/CMakeLists.txt | 14 +-
contrib/buildsystems/Generators/Vcxproj.pm | 11 +-
contrib/completion/git-prompt.sh | 7 +-
refs.c | 27 +-
refs.h | 3 +
refs/refs-internal.h | 1 +
refs/reftable-backend.c | 1435 +++++++++++++++++
reftable/.gitattributes | 1 +
reftable/LICENSE | 31 +
reftable/VERSION | 1 +
reftable/basics.c | 128 ++
reftable/basics.h | 60 +
reftable/basics_test.c | 98 ++
reftable/block.c | 440 +++++
reftable/block.h | 127 ++
reftable/block_test.c | 121 ++
reftable/blocksource.c | 148 ++
reftable/blocksource.h | 22 +
reftable/constants.h | 21 +
reftable/dump.c | 213 +++
reftable/error.c | 41 +
reftable/iter.c | 248 +++
reftable/iter.h | 75 +
reftable/merged.c | 366 +++++
reftable/merged.h | 35 +
reftable/merged_test.c | 343 ++++
reftable/pq.c | 115 ++
reftable/pq.h | 32 +
reftable/publicbasics.c | 58 +
reftable/reader.c | 733 +++++++++
reftable/reader.h | 75 +
reftable/record.c | 1157 +++++++++++++
reftable/record.h | 139 ++
reftable/record_test.c | 398 +++++
reftable/refname.c | 209 +++
reftable/refname.h | 29 +
reftable/refname_test.c | 102 ++
reftable/reftable-blocksource.h | 49 +
reftable/reftable-error.h | 62 +
reftable/reftable-generic.h | 48 +
reftable/reftable-iterator.h | 37 +
reftable/reftable-malloc.h | 18 +
reftable/reftable-merged.h | 68 +
reftable/reftable-reader.h | 89 +
reftable/reftable-record.h | 100 ++
reftable/reftable-stack.h | 120 ++
reftable/reftable-tests.h | 22 +
reftable/reftable-writer.h | 147 ++
reftable/reftable.c | 98 ++
reftable/reftable_test.c | 580 +++++++
reftable/stack.c | 1260 +++++++++++++++
reftable/stack.h | 41 +
reftable/stack_test.c | 803 +++++++++
reftable/system.h | 32 +
reftable/test_framework.c | 23 +
reftable/test_framework.h | 53 +
reftable/tree.c | 63 +
reftable/tree.h | 34 +
reftable/tree_test.c | 61 +
reftable/writer.c | 681 ++++++++
reftable/writer.h | 50 +
reftable/zlib-compat.c | 92 ++
repository.c | 2 +
repository.h | 3 +
setup.c | 9 +-
t/helper/test-reftable.c | 20 +
t/helper/test-tool.c | 4 +-
t/helper/test-tool.h | 2 +
t/t0031-reftable.sh | 199 +++
t/t0032-reftable-unittest.sh | 15 +
t/t1409-avoid-packing-refs.sh | 6 +
t/t1450-fsck.sh | 6 +
t/t3210-pack-refs.sh | 6 +
t/test-lib.sh | 5 +
82 files changed, 12112 insertions(+), 40 deletions(-)
create mode 100644 refs/reftable-backend.c
create mode 100644 reftable/.gitattributes
create mode 100644 reftable/LICENSE
create mode 100644 reftable/VERSION
create mode 100644 reftable/basics.c
create mode 100644 reftable/basics.h
create mode 100644 reftable/basics_test.c
create mode 100644 reftable/block.c
create mode 100644 reftable/block.h
create mode 100644 reftable/block_test.c
create mode 100644 reftable/blocksource.c
create mode 100644 reftable/blocksource.h
create mode 100644 reftable/constants.h
create mode 100644 reftable/dump.c
create mode 100644 reftable/error.c
create mode 100644 reftable/iter.c
create mode 100644 reftable/iter.h
create mode 100644 reftable/merged.c
create mode 100644 reftable/merged.h
create mode 100644 reftable/merged_test.c
create mode 100644 reftable/pq.c
create mode 100644 reftable/pq.h
create mode 100644 reftable/publicbasics.c
create mode 100644 reftable/reader.c
create mode 100644 reftable/reader.h
create mode 100644 reftable/record.c
create mode 100644 reftable/record.h
create mode 100644 reftable/record_test.c
create mode 100644 reftable/refname.c
create mode 100644 reftable/refname.h
create mode 100644 reftable/refname_test.c
create mode 100644 reftable/reftable-blocksource.h
create mode 100644 reftable/reftable-error.h
create mode 100644 reftable/reftable-generic.h
create mode 100644 reftable/reftable-iterator.h
create mode 100644 reftable/reftable-malloc.h
create mode 100644 reftable/reftable-merged.h
create mode 100644 reftable/reftable-reader.h
create mode 100644 reftable/reftable-record.h
create mode 100644 reftable/reftable-stack.h
create mode 100644 reftable/reftable-tests.h
create mode 100644 reftable/reftable-writer.h
create mode 100644 reftable/reftable.c
create mode 100644 reftable/reftable_test.c
create mode 100644 reftable/stack.c
create mode 100644 reftable/stack.h
create mode 100644 reftable/stack_test.c
create mode 100644 reftable/system.h
create mode 100644 reftable/test_framework.c
create mode 100644 reftable/test_framework.h
create mode 100644 reftable/tree.c
create mode 100644 reftable/tree.h
create mode 100644 reftable/tree_test.c
create mode 100644 reftable/writer.c
create mode 100644 reftable/writer.h
create mode 100644 reftable/zlib-compat.c
create mode 100644 t/helper/test-reftable.c
create mode 100755 t/t0031-reftable.sh
create mode 100755 t/t0032-reftable-unittest.sh
base-commit: 3a0b884caba2752da0af626fb2de7d597c844e8b
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-847%2Fhanwen%2Flibreftable-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-847/hanwen/libreftable-v4
Pull-Request: https://github.com/git/git/pull/847
Range-diff vs v3:
1: 030998a732a < -: ----------- move sleep_millisec to git-compat-util.h
2: cf667653dff < -: ----------- init-db: set the_repository->hash_algo early on
-: ----------- > 1: 40ac041d0ef init-db: set the_repository->hash_algo early on
3: 91c3ac2449e = 2: cc0fe58bd33 reftable: add LICENSE
4: 2aa30f536fb ! 3: 798f680b800 reftable: add error related functionality
@@ reftable/error.c (new)
+ return "zlib failure";
+ case REFTABLE_NAME_CONFLICT:
+ return "file/directory conflict";
++ case REFTABLE_EMPTY_TABLE_ERROR:
++ return "wrote empty table";
+ case REFTABLE_REFNAME_ERROR:
+ return "invalid refname";
+ case -1:
@@ reftable/reftable-error.h (new)
+#define REFTABLE_ERROR_H
+
+/*
-+ Errors in reftable calls are signaled with negative integer return values. 0
-+ means success.
-+*/
++ * Errors in reftable calls are signaled with negative integer return values. 0
++ * means success.
++ */
+enum reftable_error {
+ /* Unexpected file system behavior */
+ REFTABLE_IO_ERROR = -2,
+
-+ /* Format inconsistency on reading data
-+ */
++ /* Format inconsistency on reading data */
+ REFTABLE_FORMAT_ERROR = -3,
+
-+ /* File does not exist. Returned from block_source_from_file(), because
-+ it needs special handling in stack.
-+ */
++ /* File does not exist. Returned from block_source_from_file(), because
++ * it needs special handling in stack.
++ */
+ REFTABLE_NOT_EXIST_ERROR = -4,
+
+ /* Trying to write out-of-date data. */
+ REFTABLE_LOCK_ERROR = -5,
+
+ /* Misuse of the API:
-+ - on writing a record with NULL refname.
-+ - on writing a reftable_ref_record outside the table limits
-+ - on writing a ref or log record before the stack's next_update_index
-+ - on writing a log record with multiline message with
-+ exact_log_message unset
-+ - on reading a reftable_ref_record from log iterator, or vice versa.
-+
-+ When a call misuses the API, the internal state of the library is kept
-+ unchanged.
-+ */
++ * - on writing a record with NULL refname.
++ * - on writing a reftable_ref_record outside the table limits
++ * - on writing a ref or log record before the stack's
++ * next_update_inde*x
++ * - on writing a log record with multiline message with
++ * exact_log_message unset
++ * - on reading a reftable_ref_record from log iterator, or vice versa.
++ *
++ * When a call misuses the API, the internal state of the library is
++ * kept unchanged.
++ */
+ REFTABLE_API_ERROR = -6,
+
+ /* Decompression error */
@@ reftable/reftable-error.h (new)
+ /* Dir/file conflict. */
+ REFTABLE_NAME_CONFLICT = -9,
+
-+ /* Illegal ref name. */
++ /* Invalid ref name. */
+ REFTABLE_REFNAME_ERROR = -10,
+};
+
5: 987d1d186fd ! 4: 2f55ff6d240 reftable: utility functions
@@ Commit message
This commit provides basic utility classes for the reftable library.
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
+ Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
## Makefile ##
@@ Makefile: TEST_BUILTINS_OBJS += test-read-cache.o
@@ Makefile: cocciclean:
$(RM) $(TEST_PROGRAMS)
$(RM) $(FUZZ_PROGRAMS)
+ ## contrib/buildsystems/CMakeLists.txt ##
+@@ contrib/buildsystems/CMakeLists.txt: parse_makefile_for_sources(libxdiff_SOURCES "XDIFF_OBJS")
+ list(TRANSFORM libxdiff_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
+ add_library(xdiff STATIC ${libxdiff_SOURCES})
+
++#reftable
++parse_makefile_for_sources(reftable_SOURCES "REFTABLE_OBJS")
++
++list(TRANSFORM reftable_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
++add_library(reftable STATIC ${reftable_SOURCES})
++
+ if(WIN32)
+ if(NOT MSVC)#use windres when compiling with gcc and clang
+ add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/git.res
+@@ contrib/buildsystems/CMakeLists.txt: endif()
+ #link all required libraries to common-main
+ add_library(common-main OBJECT ${CMAKE_SOURCE_DIR}/common-main.c)
+
+-target_link_libraries(common-main libgit xdiff ${ZLIB_LIBRARIES})
++target_link_libraries(common-main libgit xdiff reftable ${ZLIB_LIBRARIES})
+ if(Intl_FOUND)
+ target_link_libraries(common-main ${Intl_LIBRARIES})
+ endif()
+@@ contrib/buildsystems/CMakeLists.txt: if(BUILD_TESTING)
+ add_executable(test-fake-ssh ${CMAKE_SOURCE_DIR}/t/helper/test-fake-ssh.c)
+ target_link_libraries(test-fake-ssh common-main)
+
++#reftable-tests
++parse_makefile_for_sources(test-reftable_SOURCES "REFTABLE_TEST_OBJS")
++list(TRANSFORM test-reftable_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
++
+ #test-tool
+ parse_makefile_for_sources(test-tool_SOURCES "TEST_BUILTINS_OBJS")
+
+ list(TRANSFORM test-tool_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/t/helper/")
+-add_executable(test-tool ${CMAKE_SOURCE_DIR}/t/helper/test-tool.c ${test-tool_SOURCES})
++add_executable(test-tool ${CMAKE_SOURCE_DIR}/t/helper/test-tool.c ${test-tool_SOURCES} ${test-reftable_SOURCES})
+ target_link_libraries(test-tool common-main)
+
+ set_target_properties(test-fake-ssh test-tool
+
## reftable/basics.c (new) ##
@@
+/*
@@ reftable/basics.c (new)
+ size_t lo = 0;
+ size_t hi = sz;
+
-+ /* invariant: (hi == sz) || f(hi) == true
-+ (lo == 0 && f(0) == true) || fi(lo) == false
++ /* Invariants:
++ *
++ * (hi == sz) || f(hi) == true
++ * (lo == 0 && f(0) == true) || fi(lo) == false
+ */
+ while (hi - lo > 1) {
+ size_t mid = lo + (hi - lo) / 2;
+
-+ int val = f(mid, args);
-+ if (val) {
++ if (f(mid, args))
+ hi = mid;
-+ } else {
++ else
+ lo = mid;
-+ }
+ }
+
-+ if (lo == 0) {
-+ if (f(0, args)) {
-+ return 0;
-+ } else {
-+ return 1;
-+ }
-+ }
++ if (lo)
++ return hi;
+
-+ return hi;
++ return f(0, args) ? 0 : 1;
+}
+
+void free_names(char **a)
+{
-+ char **p = a;
-+ if (p == NULL) {
++ char **p;
++ if (a == NULL) {
+ return;
+ }
-+ while (*p) {
++ for (p = a; *p; p++) {
+ reftable_free(*p);
-+ p++;
+ }
+ reftable_free(a);
+}
+
+int names_length(char **names)
+{
-+ int len = 0;
+ char **p = names;
-+ while (*p) {
-+ p++;
-+ len++;
++ for (; *p; p++) {
++ /* empty */
+ }
-+ return len;
++ return p - names;
+}
+
+void parse_names(char *buf, int size, char ***namesp)
@@ reftable/basics.c (new)
+ char *end = buf + size;
+ while (p < end) {
+ char *next = strchr(p, '\n');
-+ if (next != NULL) {
++ if (next && next < end) {
+ *next = 0;
+ } else {
+ next = end;
@@ reftable/basics.c (new)
+ if (names_len == names_cap) {
+ names_cap = 2 * names_cap + 1;
+ names = reftable_realloc(
-+ names, names_cap * sizeof(char *));
++ names, names_cap * sizeof(*names));
+ }
+ names[names_len++] = xstrdup(p);
+ }
+ p = next + 1;
+ }
+
-+ if (names_len == names_cap) {
-+ names_cap = 2 * names_cap + 1;
-+ names = reftable_realloc(names, names_cap * sizeof(char *));
-+ }
-+
++ names = reftable_realloc(names, (names_len + 1) * sizeof(*names));
+ names[names_len] = NULL;
+ *namesp = names;
+}
+
+int names_equal(char **a, char **b)
+{
-+ while (*a && *b) {
-+ if (strcmp(*a, *b)) {
++ int i = 0;
++ for (; a[i] && b[i]; i++) {
++ if (strcmp(a[i], b[i])) {
+ return 0;
+ }
-+
-+ a++;
-+ b++;
+ }
+
-+ return *a == *b;
++ return a[i] == b[i];
+}
+
+int common_prefix_size(struct strbuf *a, struct strbuf *b)
+{
+ int p = 0;
-+ while (p < a->len && p < b->len) {
-+ if (a->buf[p] != b->buf[p]) {
++ for (; p < a->len && p < b->len; p++) {
++ if (a->buf[p] != b->buf[p])
+ break;
-+ }
-+ p++;
+ }
+
+ return p;
@@ reftable/basics.h (new)
+void put_be16(uint8_t *out, uint16_t i);
+
+/*
-+ find smallest index i in [0, sz) at which f(i) is true, assuming
-+ that f is ascending. Return sz if f(i) is false for all indices.
-+*/
++ * find smallest index i in [0, sz) at which f(i) is true, assuming
++ * that f is ascending. Return sz if f(i) is false for all indices.
++ *
++ * Contrary to bsearch(3), this returns something useful if the argument is not
++ * found.
++ */
+int binsearch(size_t sz, int (*f)(size_t k, void *args), void *args);
+
+/*
-+ Frees a NULL terminated array of malloced strings. The array itself is also
-+ freed.
++ * Frees a NULL terminated array of malloced strings. The array itself is also
++ * freed.
+ */
+void free_names(char **a);
+
-+/* parse a newline separated list of names. Empty names are discarded. */
++/* parse a newline separated list of names. `size` is the length of the buffer,
++ * without terminating '\0'. Empty names are discarded. */
+void parse_names(char *buf, int size, char ***namesp);
+
+/* compares two NULL-terminated arrays of strings. */
@@ reftable/basics_test.c (new)
+ }
+}
+
-+int basics_test_main(int argc, const char *argv[])
++static void test_names_length(void)
+{
-+ test_binsearch();
-+ return 0;
++ char *a[] = { "a", "b", NULL };
++ EXPECT(names_length(a) == 2);
+}
-
- ## reftable/compat.h (new) ##
-@@
-+/*
-+Copyright 2020 Google LLC
-+
-+Use of this source code is governed by a BSD-style
-+license that can be found in the LICENSE file or at
-+https://developers.google.com/open-source/licenses/bsd
-+*/
-+
-+#ifndef COMPAT_H
-+#define COMPAT_H
+
-+#include "system.h"
-+
-+#ifdef REFTABLE_STANDALONE
-+
-+/* functions that git-core provides, for standalone compilation */
-+#include <stdint.h>
-+
-+uint64_t get_be64(void *in);
-+void put_be64(void *out, uint64_t i);
-+
-+void put_be32(void *out, uint32_t i);
-+uint32_t get_be32(uint8_t *in);
-+
-+uint16_t get_be16(uint8_t *in);
-+
-+#define ARRAY_SIZE(a) sizeof((a)) / sizeof((a)[0])
-+#define FREE_AND_NULL(x) \
-+ do { \
-+ reftable_free(x); \
-+ (x) = NULL; \
-+ } while (0)
-+#define QSORT(arr, n, cmp) qsort(arr, n, sizeof(arr[0]), cmp)
-+#define SWAP(a, b) \
-+ { \
-+ char tmp[sizeof(a)]; \
-+ assert(sizeof(a) == sizeof(b)); \
-+ memcpy(&tmp[0], &a, sizeof(a)); \
-+ memcpy(&a, &b, sizeof(a)); \
-+ memcpy(&b, &tmp[0], sizeof(a)); \
-+ }
++static void test_parse_names_normal(void)
++{
++ char in[] = "a\nb\n";
++ char **out = NULL;
++ parse_names(in, strlen(in), &out);
++ EXPECT(!strcmp(out[0], "a"));
++ EXPECT(!strcmp(out[1], "b"));
++ EXPECT(out[2] == NULL);
++ free_names(out);
++}
+
-+char *xstrdup(const char *s);
++static void test_parse_names_drop_empty(void)
++{
++ char in[] = "a\n\n";
++ char **out = NULL;
++ parse_names(in, strlen(in), &out);
++ EXPECT(!strcmp(out[0], "a"));
++ EXPECT(out[1] == NULL);
++ free_names(out);
++}
+
-+void sleep_millisec(int millisecs);
++static void test_common_prefix(void)
++{
++ struct strbuf s1 = STRBUF_INIT;
++ struct strbuf s2 = STRBUF_INIT;
++ strbuf_addstr(&s1, "abcdef");
++ strbuf_addstr(&s2, "abc");
++ EXPECT(common_prefix_size(&s1, &s2) == 3);
++ strbuf_release(&s1);
++ strbuf_release(&s2);
++}
+
-+#endif
-+#endif
++int basics_test_main(int argc, const char *argv[])
++{
++ RUN_TEST(test_common_prefix);
++ RUN_TEST(test_parse_names_normal);
++ RUN_TEST(test_parse_names_drop_empty);
++ RUN_TEST(test_binsearch);
++ RUN_TEST(test_names_length);
++ return 0;
++}
## reftable/publicbasics.c (new) ##
@@
@@ reftable/reftable-malloc.h (new)
+
+#include <stddef.h>
+
-+/*
-+ Overrides the functions to use for memory management.
-+ */
++/* Overrides the functions to use for memory management. */
+void reftable_set_alloc(void *(*malloc)(size_t),
+ void *(*realloc)(void *, size_t), void (*free)(void *));
+
@@ reftable/test_framework.h (new)
+ abort(); \
+ }
+
++#define RUN_TEST(f) \
++ fprintf(stderr, "running %s\n", #f); \
++ fflush(stderr); \
++ f();
++
+void set_test_hash(uint8_t *p, int i);
+
+/* Like strbuf_add, but suitable for passing to reftable_new_writer
@@ t/t0032-reftable-unittest.sh (new)
+. ./test-lib.sh
+
+test_expect_success 'unittests' '
-+ test-tool reftable
++ TMPDIR=$(pwd) && export TMPDIR &&
++ test-tool reftable
+'
+
+test_done
6: f71e82b995d ! 5: aaa817f8598 reftable: add blocksource, an abstraction for random access reads
@@ reftable/reftable-blocksource.h (new)
+};
+
+/* a contiguous segment of bytes. It keeps track of its generating block_source
-+ so it can return itself into the pool.
-+*/
++ * so it can return itself into the pool. */
+struct reftable_block {
+ uint8_t *data;
+ int len;
7: bbe2ed71734 ! 6: e13afe31525 reftable: (de)serialization for the polymorphic record type.
@@ reftable/record.c (new)
+ return 0;
+}
+
++uint8_t *reftable_ref_record_val1(struct reftable_ref_record *rec)
++{
++ switch (rec->value_type) {
++ case REFTABLE_REF_VAL1:
++ return rec->value.val1;
++ case REFTABLE_REF_VAL2:
++ return rec->value.val2.value;
++ default:
++ return NULL;
++ }
++}
++
++uint8_t *reftable_ref_record_val2(struct reftable_ref_record *rec)
++{
++ switch (rec->value_type) {
++ case REFTABLE_REF_VAL2:
++ return rec->value.val2.target_value;
++ default:
++ return NULL;
++ }
++}
++
+static int decode_string(struct strbuf *dest, struct string_view in)
+{
+ int start_len = in.len;
@@ reftable/record.c (new)
+ assert(hash_size > 0);
+
+ /* This is simple and correct, but we could probably reuse the hash
-+ fields. */
++ * fields. */
+ reftable_ref_record_release(ref);
+ if (src->refname != NULL) {
+ ref->refname = xstrdup(src->refname);
+ }
-+
-+ if (src->target != NULL) {
-+ ref->target = xstrdup(src->target);
-+ }
-+
-+ if (src->target_value != NULL) {
-+ ref->target_value = reftable_malloc(hash_size);
-+ memcpy(ref->target_value, src->target_value, hash_size);
-+ }
-+
-+ if (src->value != NULL) {
-+ ref->value = reftable_malloc(hash_size);
-+ memcpy(ref->value, src->value, hash_size);
-+ }
+ ref->update_index = src->update_index;
++ ref->value_type = src->value_type;
++ switch (src->value_type) {
++ case REFTABLE_REF_DELETION:
++ break;
++ case REFTABLE_REF_VAL1:
++ ref->value.val1 = reftable_malloc(hash_size);
++ memcpy(ref->value.val1, src->value.val1, hash_size);
++ break;
++ case REFTABLE_REF_VAL2:
++ ref->value.val2.value = reftable_malloc(hash_size);
++ memcpy(ref->value.val2.value, src->value.val2.value, hash_size);
++ ref->value.val2.target_value = reftable_malloc(hash_size);
++ memcpy(ref->value.val2.target_value,
++ src->value.val2.target_value, hash_size);
++ break;
++ case REFTABLE_REF_SYMREF:
++ ref->value.symref = xstrdup(src->value.symref);
++ break;
++ }
+}
+
+static char hexdigit(int c)
@@ reftable/record.c (new)
+void reftable_ref_record_print(struct reftable_ref_record *ref,
+ uint32_t hash_id)
+{
-+ char hex[SHA256_SIZE + 1] = { 0 };
++ char hex[2 * SHA256_SIZE + 1] = { 0 }; /* BUG */
+ printf("ref{%s(%" PRIu64 ") ", ref->refname, ref->update_index);
-+ if (ref->value != NULL) {
-+ hex_format(hex, ref->value, hash_size(hash_id));
-+ printf("%s", hex);
-+ }
-+ if (ref->target_value != NULL) {
-+ hex_format(hex, ref->target_value, hash_size(hash_id));
-+ printf(" (T %s)", hex);
-+ }
-+ if (ref->target != NULL) {
-+ printf("=> %s", ref->target);
++ switch (ref->value_type) {
++ case REFTABLE_REF_SYMREF:
++ printf("=> %s", ref->value.symref);
++ break;
++ case REFTABLE_REF_VAL2:
++ hex_format(hex, ref->value.val2.value, hash_size(hash_id));
++ printf("val 2 %s", hex);
++ hex_format(hex, ref->value.val2.target_value,
++ hash_size(hash_id));
++ printf("(T %s)", hex);
++ break;
++ case REFTABLE_REF_VAL1:
++ hex_format(hex, ref->value.val1, hash_size(hash_id));
++ printf("val 1 %s", hex);
++ break;
++ case REFTABLE_REF_DELETION:
++ printf("delete");
++ break;
+ }
+ printf("}\n");
+}
@@ reftable/record.c (new)
+
+void reftable_ref_record_release(struct reftable_ref_record *ref)
+{
++ switch (ref->value_type) {
++ case REFTABLE_REF_SYMREF:
++ reftable_free(ref->value.symref);
++ break;
++ case REFTABLE_REF_VAL2:
++ reftable_free(ref->value.val2.target_value);
++ reftable_free(ref->value.val2.value);
++ break;
++ case REFTABLE_REF_VAL1:
++ reftable_free(ref->value.val1);
++ break;
++ case REFTABLE_REF_DELETION:
++ break;
++ default:
++ abort();
++ }
++
+ reftable_free(ref->refname);
-+ reftable_free(ref->target);
-+ reftable_free(ref->target_value);
-+ reftable_free(ref->value);
+ memset(ref, 0, sizeof(struct reftable_ref_record));
+}
+
@@ reftable/record.c (new)
+{
+ const struct reftable_ref_record *r =
+ (const struct reftable_ref_record *)rec;
-+ if (r->value != NULL) {
-+ if (r->target_value != NULL) {
-+ return 2;
-+ } else {
-+ return 1;
-+ }
-+ } else if (r->target != NULL)
-+ return 3;
-+ return 0;
++ return r->value_type;
+}
+
+static int reftable_ref_record_encode(const void *rec, struct string_view s,
@@ reftable/record.c (new)
+ return -1;
+ string_view_consume(&s, n);
+
-+ if (r->value != NULL) {
-+ if (s.len < hash_size) {
++ switch (r->value_type) {
++ case REFTABLE_REF_SYMREF:
++ n = encode_string(r->value.symref, s);
++ if (n < 0) {
+ return -1;
+ }
-+ memcpy(s.buf, r->value, hash_size);
-+ string_view_consume(&s, hash_size);
-+ }
-+
-+ if (r->target_value != NULL) {
-+ if (s.len < hash_size) {
++ string_view_consume(&s, n);
++ break;
++ case REFTABLE_REF_VAL2:
++ if (s.len < 2 * hash_size) {
+ return -1;
+ }
-+ memcpy(s.buf, r->target_value, hash_size);
++ memcpy(s.buf, r->value.val2.value, hash_size);
+ string_view_consume(&s, hash_size);
-+ }
-+
-+ if (r->target != NULL) {
-+ int n = encode_string(r->target, s);
-+ if (n < 0) {
++ memcpy(s.buf, r->value.val2.target_value, hash_size);
++ string_view_consume(&s, hash_size);
++ break;
++ case REFTABLE_REF_VAL1:
++ if (s.len < hash_size) {
+ return -1;
+ }
-+ string_view_consume(&s, n);
++ memcpy(s.buf, r->value.val1, hash_size);
++ string_view_consume(&s, hash_size);
++ break;
++ case REFTABLE_REF_DELETION:
++ break;
++ default:
++ abort();
+ }
+
+ return start.len - s.len;
@@ reftable/record.c (new)
+{
+ struct reftable_ref_record *r = (struct reftable_ref_record *)rec;
+ struct string_view start = in;
-+ int seen_value = 0;
-+ int seen_target_value = 0;
-+ int seen_target = 0;
-+
-+ int n = get_var_int(&r->update_index, &in);
++ uint64_t update_index = 0;
++ int n = get_var_int(&update_index, &in);
+ if (n < 0)
+ return n;
-+ assert(hash_size > 0);
-+
+ string_view_consume(&in, n);
+
++ reftable_ref_record_release(r);
++
++ assert(hash_size > 0);
++
+ r->refname = reftable_realloc(r->refname, key.len + 1);
+ memcpy(r->refname, key.buf, key.len);
++ r->update_index = update_index;
+ r->refname[key.len] = 0;
-+
++ r->value_type = val_type;
+ switch (val_type) {
-+ case 1:
-+ case 2:
++ case REFTABLE_REF_VAL1:
+ if (in.len < hash_size) {
+ return -1;
+ }
+
-+ if (r->value == NULL) {
-+ r->value = reftable_malloc(hash_size);
-+ }
-+ seen_value = 1;
-+ memcpy(r->value, in.buf, hash_size);
++ r->value.val1 = reftable_malloc(hash_size);
++ memcpy(r->value.val1, in.buf, hash_size);
+ string_view_consume(&in, hash_size);
-+ if (val_type == 1) {
-+ break;
-+ }
-+ if (r->target_value == NULL) {
-+ r->target_value = reftable_malloc(hash_size);
++ break;
++
++ case REFTABLE_REF_VAL2:
++ if (in.len < 2 * hash_size) {
++ return -1;
+ }
-+ seen_target_value = 1;
-+ memcpy(r->target_value, in.buf, hash_size);
++
++ r->value.val2.value = reftable_malloc(hash_size);
++ memcpy(r->value.val2.value, in.buf, hash_size);
++ string_view_consume(&in, hash_size);
++
++ r->value.val2.target_value = reftable_malloc(hash_size);
++ memcpy(r->value.val2.target_value, in.buf, hash_size);
+ string_view_consume(&in, hash_size);
+ break;
-+ case 3: {
++
++ case REFTABLE_REF_SYMREF: {
+ struct strbuf dest = STRBUF_INIT;
+ int n = decode_string(&dest, in);
+ if (n < 0) {
+ return -1;
+ }
+ string_view_consume(&in, n);
-+ seen_target = 1;
-+ if (r->target != NULL) {
-+ reftable_free(r->target);
-+ }
-+ r->target = dest.buf;
++ r->value.symref = dest.buf;
+ } break;
+
-+ case 0:
++ case REFTABLE_REF_DELETION:
+ break;
+ default:
+ abort();
+ break;
+ }
+
-+ if (!seen_target && r->target != NULL) {
-+ FREE_AND_NULL(r->target);
-+ }
-+ if (!seen_target_value && r->target_value != NULL) {
-+ FREE_AND_NULL(r->target_value);
-+ }
-+ if (!seen_value && r->value != NULL) {
-+ FREE_AND_NULL(r->value);
-+ }
-+
+ return start.len - in.len;
+}
+
@@ reftable/record.c (new)
+ return a == b;
+}
+
-+static int str_equal(char *a, char *b)
-+{
-+ if (a != NULL && b != NULL)
-+ return 0 == strcmp(a, b);
-+
-+ return a == b;
-+}
-+
+int reftable_ref_record_equal(struct reftable_ref_record *a,
+ struct reftable_ref_record *b, int hash_size)
+{
+ assert(hash_size > 0);
-+ return 0 == strcmp(a->refname, b->refname) &&
-+ a->update_index == b->update_index &&
-+ hash_equal(a->value, b->value, hash_size) &&
-+ hash_equal(a->target_value, b->target_value, hash_size) &&
-+ str_equal(a->target, b->target);
++ if (!(0 == strcmp(a->refname, b->refname) &&
++ a->update_index == b->update_index &&
++ a->value_type == b->value_type))
++ return 0;
++
++ switch (a->value_type) {
++ case REFTABLE_REF_SYMREF:
++ return !strcmp(a->value.symref, b->value.symref);
++ case REFTABLE_REF_VAL2:
++ return hash_equal(a->value.val2.value, b->value.val2.value,
++ hash_size) &&
++ hash_equal(a->value.val2.target_value,
++ b->value.val2.target_value, hash_size);
++ case REFTABLE_REF_VAL1:
++ return hash_equal(a->value.val1, b->value.val1, hash_size);
++ case REFTABLE_REF_DELETION:
++ return 1;
++ default:
++ abort();
++ }
+}
+
+int reftable_ref_record_compare_name(const void *a, const void *b)
@@ reftable/record.c (new)
+
+int reftable_ref_record_is_deletion(const struct reftable_ref_record *ref)
+{
-+ return ref->value == NULL && ref->target == NULL &&
-+ ref->target_value == NULL;
++ return ref->value_type == REFTABLE_REF_DELETION;
+}
+
+int reftable_log_record_compare_key(const void *a, const void *b)
@@ reftable/record.h (new)
+#include "reftable-record.h"
+
+/*
-+ A substring of existing string data. This structure takes no responsibility
-+ for the lifetime of the data it points to.
-+*/
++ * A substring of existing string data. This structure takes no responsibility
++ * for the lifetime of the data it points to.
++ */
+struct string_view {
+ uint8_t *buf;
+ size_t len;
@@ reftable/record.h (new)
+struct reftable_record reftable_new_record(uint8_t typ);
+
+/* Encode `key` into `dest`. Sets `is_restart` to indicate a restart. Returns
-+ number of bytes written. */
++ * number of bytes written. */
+int reftable_encode_key(int *is_restart, struct string_view dest,
+ struct strbuf prev_key, struct strbuf key,
+ uint8_t extra);
@@ reftable/record_test.c (new)
+{
+ int i = 0;
+
-+ for (i = 0; i <= 3; i++) {
++ for (i = REFTABLE_REF_DELETION; i < REFTABLE_NR_REF_VALUETYPES; i++) {
+ struct reftable_ref_record in = { NULL };
-+ struct reftable_ref_record out = {
-+ .refname = xstrdup("old name"),
-+ .value = reftable_calloc(SHA1_SIZE),
-+ .target_value = reftable_calloc(SHA1_SIZE),
-+ .target = xstrdup("old value"),
-+ };
++ struct reftable_ref_record out = { NULL };
+ struct reftable_record rec_out = { NULL };
+ struct strbuf key = STRBUF_INIT;
+ struct reftable_record rec = { NULL };
@@ reftable/record_test.c (new)
+
+ int n, m;
+
++ in.value_type = i;
+ switch (i) {
-+ case 0:
++ case REFTABLE_REF_DELETION:
+ break;
-+ case 1:
-+ in.value = reftable_malloc(SHA1_SIZE);
-+ set_hash(in.value, 1);
++ case REFTABLE_REF_VAL1:
++ in.value.val1 = reftable_malloc(SHA1_SIZE);
++ set_hash(in.value.val1, 1);
+ break;
-+ case 2:
-+ in.value = reftable_malloc(SHA1_SIZE);
-+ set_hash(in.value, 1);
-+ in.target_value = reftable_malloc(SHA1_SIZE);
-+ set_hash(in.target_value, 2);
++ case REFTABLE_REF_VAL2:
++ in.value.val2.value = reftable_malloc(SHA1_SIZE);
++ set_hash(in.value.val2.value, 1);
++ in.value.val2.target_value = reftable_malloc(SHA1_SIZE);
++ set_hash(in.value.val2.target_value, 2);
+ break;
-+ case 3:
-+ in.target = xstrdup("target");
++ case REFTABLE_REF_SYMREF:
++ in.value.symref = xstrdup("target");
+ break;
+ }
+ in.refname = xstrdup("refs/heads/master");
@@ reftable/record_test.c (new)
+ m = reftable_record_decode(&rec_out, key, i, dest, SHA1_SIZE);
+ EXPECT(n == m);
+
-+ EXPECT((out.value != NULL) == (in.value != NULL));
-+ EXPECT((out.target_value != NULL) == (in.target_value != NULL));
-+ EXPECT((out.target != NULL) == (in.target != NULL));
++ EXPECT(reftable_ref_record_equal(&in, &out, SHA1_SIZE));
+ reftable_record_release(&rec_out);
+
+ strbuf_release(&key);
@@ reftable/record_test.c (new)
+
+int record_test_main(int argc, const char *argv[])
+{
-+ test_reftable_log_record_equal();
-+ test_reftable_log_record_roundtrip();
-+ test_reftable_ref_record_roundtrip();
-+ test_varint_roundtrip();
-+ test_key_roundtrip();
-+ test_common_prefix();
-+ test_reftable_obj_record_roundtrip();
-+ test_reftable_index_record_roundtrip();
-+ test_u24_roundtrip();
++ RUN_TEST(test_reftable_log_record_equal);
++ RUN_TEST(test_reftable_log_record_roundtrip);
++ RUN_TEST(test_reftable_ref_record_roundtrip);
++ RUN_TEST(test_varint_roundtrip);
++ RUN_TEST(test_key_roundtrip);
++ RUN_TEST(test_common_prefix);
++ RUN_TEST(test_reftable_obj_record_roundtrip);
++ RUN_TEST(test_reftable_index_record_roundtrip);
++ RUN_TEST(test_u24_roundtrip);
+ return 0;
+}
@@ reftable/reftable-record.h (new)
+#include <stdint.h>
+
+/*
-+ Basic data types
-+
-+ Reftables store the state of each ref in struct reftable_ref_record, and they
-+ store a sequence of reflog updates in struct reftable_log_record.
-+*/
++ * Basic data types
++ *
++ * Reftables store the state of each ref in struct reftable_ref_record, and they
++ * store a sequence of reflog updates in struct reftable_log_record.
++ */
+
+/* reftable_ref_record holds a ref database entry target_value */
+struct reftable_ref_record {
+ char *refname; /* Name of the ref, malloced. */
+ uint64_t update_index; /* Logical timestamp at which this value is
-+ written */
-+ uint8_t *value; /* SHA1, or NULL. malloced. */
-+ uint8_t *target_value; /* peeled annotated tag, or NULL. malloced. */
-+ char *target; /* symref, or NULL. malloced. */
++ * written */
++
++ enum {
++ /* tombstone to hide deletions from earlier tables */
++ REFTABLE_REF_DELETION = 0x0,
++
++ /* a simple ref */
++ REFTABLE_REF_VAL1 = 0x1,
++ /* a tag, plus its peeled hash */
++ REFTABLE_REF_VAL2 = 0x2,
++
++ /* a symbolic reference */
++ REFTABLE_REF_SYMREF = 0x3,
++#define REFTABLE_NR_REF_VALUETYPES 4
++ } value_type;
++ union {
++ uint8_t *val1; /* malloced hash. */
++ struct {
++ uint8_t *value; /* first value, malloced hash */
++ uint8_t *target_value; /* second value, malloced hash */
++ } val2;
++ char *symref; /* referent, malloced 0-terminated string */
++ } value;
+};
+
++/* Returns the first hash, or NULL if `rec` is not of type
++ * REFTABLE_REF_VAL1 or REFTABLE_REF_VAL2. */
++uint8_t *reftable_ref_record_val1(struct reftable_ref_record *rec);
++
++/* Returns the second hash, or NULL if `rec` is not of type
++ * REFTABLE_REF_VAL2. */
++uint8_t *reftable_ref_record_val2(struct reftable_ref_record *rec);
++
+/* returns whether 'ref' represents a deletion */
+int reftable_ref_record_is_deletion(const struct reftable_ref_record *ref);
+
-+/* prints a reftable_ref_record onto stdout */
++/* prints a reftable_ref_record onto stdout. Useful for debugging. */
+void reftable_ref_record_print(struct reftable_ref_record *ref,
+ uint32_t hash_id);
+
-+/* frees and nulls all pointer values. */
++/* frees and nulls all pointer values inside `ref`. */
+void reftable_ref_record_release(struct reftable_ref_record *ref);
+
-+/* returns whether two reftable_ref_records are the same */
++/* returns whether two reftable_ref_records are the same. Useful for testing. */
+int reftable_ref_record_equal(struct reftable_ref_record *a,
+ struct reftable_ref_record *b, int hash_size);
+
8: a358b052d56 ! 7: a48b9937642 reftable: reading/writing blocks
@@ reftable/block.h (new)
+#include "reftable-blocksource.h"
+
+/*
-+ Writes reftable blocks. The block_writer is reused across blocks to minimize
-+ allocation overhead.
-+*/
++ * Writes reftable blocks. The block_writer is reused across blocks to minimize
++ * allocation overhead.
++ */
+struct block_writer {
+ uint8_t *buf;
+ uint32_t block_size;
@@ reftable/block.h (new)
+};
+
+/*
-+ initializes the blockwriter to write `typ` entries, using `buf` as temporary
-+ storage. `buf` is not owned by the block_writer. */
++ * initializes the blockwriter to write `typ` entries, using `buf` as temporary
++ * storage. `buf` is not owned by the block_writer. */
+void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
+ uint32_t block_size, uint32_t header_off, int hash_size);
+
-+/*
-+ returns the block type (eg. 'r' for ref records.
-+*/
++/* returns the block type (eg. 'r' for ref records. */
+uint8_t block_writer_type(struct block_writer *bw);
+
+/* appends the record, or -1 if it doesn't fit. */
@@ reftable/block_test.c (new)
+ memset(hash, i, sizeof(hash));
+
+ ref.refname = name;
-+ ref.value = hash;
++ ref.value_type = REFTABLE_REF_VAL1;
++ ref.value.val1 = hash;
++
+ names[i] = xstrdup(name);
+ n = block_writer_add(&bw, &rec);
+ ref.refname = NULL;
-+ ref.value = NULL;
++ ref.value_type = REFTABLE_REF_DELETION;
+ EXPECT(n == 0);
+ }
+
@@ reftable/block_test.c (new)
+
+int block_test_main(int argc, const char *argv[])
+{
-+ test_block_read_write();
++ RUN_TEST(test_block_read_write);
+ return 0;
+}
9: 24afac9c91a ! 8: 6968dbc3828 reftable: a generic binary tree implementation
@@ reftable/tree.h (new)
+};
+
+/* looks for `key` in `rootp` using `compare` as comparison function. If insert
-+ is set, insert the key if it's not found. Else, return NULL.
-+*/
++ * is set, insert the key if it's not found. Else, return NULL.
++ */
+struct tree_node *tree_search(void *key, struct tree_node **rootp,
+ int (*compare)(const void *, const void *),
+ int insert);
@@ reftable/tree.h (new)
+ void *arg);
+
+/*
-+ deallocates the tree nodes recursively. Keys should be deallocated separately
-+ by walking over the tree. */
++ * deallocates the tree nodes recursively. Keys should be deallocated separately
++ * by walking over the tree. */
+void tree_free(struct tree_node *t);
+
+#endif
@@ reftable/tree_test.c (new)
+
+int tree_test_main(int argc, const char *argv[])
+{
-+ test_tree();
++ RUN_TEST(test_tree);
+ return 0;
+}
10: 5f0b7c55925 ! 9: ff5b424d12f reftable: write reftable files
@@ reftable/reftable-writer.h (new)
+
+#include "reftable-record.h"
+
-+/*
-+ Writing single reftables
-+*/
++/* Writing single reftables */
+
+/* reftable_write_options sets options for writing a single reftable. */
+struct reftable_write_options {
@@ reftable/writer.c (new)
+
+ reftable_record_from_ref(&rec, ©);
+ copy.update_index -= w->min_update_index;
++
+ err = writer_add_record(w, &rec);
+ if (err < 0)
+ return err;
+
-+ if (!w->opts.skip_index_objects && ref->value != NULL) {
++ if (!w->opts.skip_index_objects &&
++ reftable_ref_record_val1(ref) != NULL) {
+ struct strbuf h = STRBUF_INIT;
-+ strbuf_add(&h, (char *)ref->value, hash_size(w->opts.hash_id));
++ strbuf_add(&h, (char *)reftable_ref_record_val1(ref),
++ hash_size(w->opts.hash_id));
+ writer_index_hash(w, &h);
+ strbuf_release(&h);
+ }
+
-+ if (!w->opts.skip_index_objects && ref->target_value != NULL) {
++ if (!w->opts.skip_index_objects &&
++ reftable_ref_record_val2(ref) != NULL) {
+ struct strbuf h = STRBUF_INIT;
-+ strbuf_add(&h, ref->target_value, hash_size(w->opts.hash_id));
++ strbuf_add(&h, reftable_ref_record_val2(ref),
++ hash_size(w->opts.hash_id));
+ writer_index_hash(w, &h);
+ strbuf_release(&h);
+ }
@@ reftable/writer.h (new)
+ size_t index_cap;
+
+ /*
-+ tree for use with tsearch; used to populate the 'o' inverse OID
-+ map */
++ * tree for use with tsearch; used to populate the 'o' inverse OID
++ * map */
+ struct tree_node *obj_index_tree;
+
+ struct reftable_stats stats;
11: 9aa2caade8c ! 10: 3c2de7dcc65 reftable: read reftable files
@@ reftable/iter.c (new)
+ }
+ }
+
-+ if ((ref->target_value != NULL &&
-+ !memcmp(fri->oid.buf, ref->target_value, fri->oid.len)) ||
-+ (ref->value != NULL &&
-+ !memcmp(fri->oid.buf, ref->value, fri->oid.len))) {
++ if (ref->value_type == REFTABLE_REF_VAL2 &&
++ (!memcmp(fri->oid.buf, ref->value.val2.target_value,
++ fri->oid.len) ||
++ !memcmp(fri->oid.buf, ref->value.val2.value,
++ fri->oid.len)))
++ return 0;
++
++ if (ref->value_type == REFTABLE_REF_VAL1 &&
++ !memcmp(fri->oid.buf, ref->value.val1, fri->oid.len)) {
+ return 0;
+ }
+ }
@@ reftable/iter.c (new)
+ }
+ continue;
+ }
-+
-+ if (!memcmp(it->oid.buf, ref->target_value, it->oid.len) ||
-+ !memcmp(it->oid.buf, ref->value, it->oid.len)) {
++ /* BUG */
++ if (!memcmp(it->oid.buf, ref->value.val2.target_value,
++ it->oid.len) ||
++ !memcmp(it->oid.buf, ref->value.val2.value, it->oid.len)) {
+ return 0;
+ }
+ }
@@ reftable/iter.h (new)
+int iterator_next(struct reftable_iterator *it, struct reftable_record *rec);
+
+/* Returns true for a zeroed out iterator, such as the one returned from
-+ iterator_destroy. */
++ * iterator_destroy. */
+int iterator_is_null(struct reftable_iterator *it);
+
+/* iterator that produces only ref records that point to `oid` */
@@ reftable/iter.h (new)
+ struct filtering_ref_iterator *);
+
+/* iterator that produces only ref records that point to `oid`,
-+ but using the object index.
++ * but using the object index.
+ */
+struct indexed_table_ref_iter {
+ struct reftable_reader *r;
@@ reftable/reftable-iterator.h (new)
+#include "reftable-record.h"
+
+/* iterator is the generic interface for walking over data stored in a
-+ reftable.
-+*/
++ * reftable.
++ */
+struct reftable_iterator {
+ struct reftable_iterator_vtable *ops;
+ void *iter_arg;
+};
+
+/* reads the next reftable_ref_record. Returns < 0 for error, 0 for OK and > 0:
-+ end of iteration.
-+*/
++ * end of iteration.
++ */
+int reftable_iterator_next_ref(struct reftable_iterator *it,
+ struct reftable_ref_record *ref);
+
+/* reads the next reftable_log_record. Returns < 0 for error, 0 for OK and > 0:
-+ end of iteration.
-+*/
++ * end of iteration.
++ */
+int reftable_iterator_next_log(struct reftable_iterator *it,
+ struct reftable_log_record *log);
+
@@ reftable/reftable-reader.h (new)
+#include "reftable-blocksource.h"
+
+/*
-+ Reading single tables
-+
-+ The follow routines are for reading single files. For an application-level
-+ interface, skip ahead to struct reftable_merged_table and struct
-+ reftable_stack.
-+*/
++ * Reading single tables
++ *
++ * The follow routines are for reading single files. For an application-level
++ * interface, skip ahead to struct reftable_merged_table and struct
++ * reftable_stack.
++ */
+
+/* The reader struct is a handle to an open reftable file. */
+struct reftable_reader;
12: 581a4200d64 ! 11: 03681b820d1 reftable: reftable file level tests
@@ reftable/reftable_test.c (new)
+ snprintf(name, sizeof(name), "refs/heads/branch%02d", i);
+
+ ref.refname = name;
-+ ref.value = hash;
+ ref.update_index = update_index;
++ ref.value_type = REFTABLE_REF_VAL1;
++ ref.value.val1 = hash;
+ (*names)[i] = xstrdup(name);
+
+ n = reftable_writer_add_ref(w, &ref);
@@ reftable/reftable_test.c (new)
+ err = reftable_iterator_next_ref(&it, &ref);
+ EXPECT_ERR(err);
+ EXPECT(0 == strcmp(names[i], ref.refname));
-+ EXPECT(i == ref.value[0]);
++ EXPECT(REFTABLE_REF_VAL1 == ref.value_type);
++ EXPECT(i == ref.value.val1[0]);
+
+ reftable_ref_record_release(&ref);
+ reftable_iterator_destroy(&it);
@@ reftable/reftable_test.c (new)
+
+ set_test_hash(hash1, i / 4);
+ set_test_hash(hash2, 3 + i / 4);
-+ ref.value = hash1;
-+ ref.target_value = hash2;
++ ref.value_type = REFTABLE_REF_VAL2;
++ ref.value.val2.value = hash1;
++ ref.value.val2.target_value = hash2;
+
+ /* 80 bytes / entry, so 3 entries per block. Yields 17
+ */
@@ reftable/reftable_test.c (new)
+
+int reftable_test_main(int argc, const char *argv[])
+{
-+ test_log_write_read();
-+ test_table_read_write_seek_linear_sha256();
-+ test_log_buffer_size();
-+ test_table_write_small_table();
-+ test_buffer();
-+ test_table_read_api();
-+ test_table_read_write_sequential();
-+ test_table_read_write_seek_linear();
-+ test_table_read_write_seek_index();
-+ test_table_refs_for_no_index();
-+ test_table_refs_for_obj_index();
-+ test_table_empty();
++ RUN_TEST(test_log_write_read);
++ RUN_TEST(test_table_read_write_seek_linear_sha256);
++ RUN_TEST(test_log_buffer_size);
++ RUN_TEST(test_table_write_small_table);
++ RUN_TEST(test_buffer);
++ RUN_TEST(test_table_read_api);
++ RUN_TEST(test_table_read_write_sequential);
++ RUN_TEST(test_table_read_write_seek_linear);
++ RUN_TEST(test_table_read_write_seek_index);
++ RUN_TEST(test_table_refs_for_no_index);
++ RUN_TEST(test_table_refs_for_obj_index);
++ RUN_TEST(test_table_empty);
+ return 0;
+}
13: a26fb180add ! 12: 557183d3e3e reftable: rest of library
@@ Makefile: REFTABLE_OBJS += reftable/error.o
## reftable/VERSION (new) ##
@@
-+b8ec0f74c74cb6752eb2033ad8e755a9c19aad15 C: add missing header
++9b4a54059db9a05c270c0a0587f245bc6868d576 C: use rand() rather than cobbled together random generator.
## reftable/dump.c (new) ##
@@
@@ reftable/merged_test.c (new)
+ struct reftable_ref_record r1[] = { {
+ .refname = "b",
+ .update_index = 1,
-+ .value = hash1,
++ .value_type = REFTABLE_REF_VAL1,
++ .value.val1 = hash1,
+ } };
+ struct reftable_ref_record r2[] = { {
+ .refname = "a",
+ .update_index = 2,
++ .value_type = REFTABLE_REF_DELETION,
+ } };
+
+ struct reftable_ref_record *refs[] = { r1, r2 };
@@ reftable/merged_test.c (new)
+{
+ uint8_t hash1[SHA1_SIZE] = { 1 };
+ uint8_t hash2[SHA1_SIZE] = { 2 };
-+ struct reftable_ref_record r1[] = { {
-+ .refname = "a",
-+ .update_index = 1,
-+ .value = hash1,
-+ },
-+ {
-+ .refname = "b",
-+ .update_index = 1,
-+ .value = hash1,
-+ },
-+ {
-+ .refname = "c",
-+ .update_index = 1,
-+ .value = hash1,
-+ } };
++ struct reftable_ref_record r1[] = {
++ {
++ .refname = "a",
++ .update_index = 1,
++ .value_type = REFTABLE_REF_VAL1,
++ .value.val1 = hash1,
++ },
++ {
++ .refname = "b",
++ .update_index = 1,
++ .value_type = REFTABLE_REF_VAL1,
++ .value.val1 = hash1,
++ },
++ {
++ .refname = "c",
++ .update_index = 1,
++ .value_type = REFTABLE_REF_VAL1,
++ .value.val1 = hash1,
++ }
++ };
+ struct reftable_ref_record r2[] = { {
+ .refname = "a",
+ .update_index = 2,
++ .value_type = REFTABLE_REF_DELETION,
+ } };
+ struct reftable_ref_record r3[] = {
+ {
+ .refname = "c",
+ .update_index = 3,
-+ .value = hash2,
++ .value_type = REFTABLE_REF_VAL1,
++ .value.val1 = hash2,
+ },
+ {
+ .refname = "d",
+ .update_index = 3,
-+ .value = hash1,
++ .value_type = REFTABLE_REF_VAL1,
++ .value.val1 = hash1,
+ },
+ };
+
@@ reftable/merged_test.c (new)
+
+int merged_test_main(int argc, const char *argv[])
+{
-+ test_merged_between();
-+ test_pq();
-+ test_merged();
-+ test_default_write_opts();
++ RUN_TEST(test_merged_between);
++ RUN_TEST(test_pq);
++ RUN_TEST(test_merged);
++ RUN_TEST(test_default_write_opts);
+ return 0;
+}
@@ reftable/refname_test.c (new)
+ reftable_new_writer(&strbuf_add_void, &buf, &opts);
+ struct reftable_ref_record rec = {
+ .refname = "a/b",
-+ .target = "destination", /* make sure it's not a symref. */
++ .value_type = REFTABLE_REF_SYMREF,
++ .value.symref = "destination", /* make sure it's not a symref.
++ */
+ .update_index = 1,
+ };
+ int err;
@@ reftable/refname_test.c (new)
+
+int refname_test_main(int argc, const char *argv[])
+{
-+ test_conflict();
++ RUN_TEST(test_conflict);
+ return 0;
+}
@@ reftable/reftable-generic.h (new)
+#include "reftable-merged.h"
+
+/*
-+ Provides a unified API for reading tables, either merged tables, or single
-+ readers.
-+*/
++ * Provides a unified API for reading tables, either merged tables, or single
++ * readers. */
+struct reftable_table {
+ struct reftable_table_vtable *ops;
+ void *table_arg;
@@ reftable/reftable-merged.h (new)
+#include "reftable-iterator.h"
+
+/*
-+ Merged tables
-+
-+ A ref database kept in a sequence of table files. The merged_table presents a
-+ unified view to reading (seeking, iterating) a sequence of immutable tables.
-+
-+ The merged tables are on purpose kept disconnected from their actual storage
-+ (eg. files on disk), because it is useful to merge tables aren't files. For
-+ example, the per-workspace and global ref namespace can be implemented as a
-+ merged table of two stacks of file-backed reftables.
-+*/
++ * Merged tables
++ *
++ * A ref database kept in a sequence of table files. The merged_table presents a
++ * unified view to reading (seeking, iterating) a sequence of immutable tables.
++ *
++ * The merged tables are on purpose kept disconnected from their actual storage
++ * (eg. files on disk), because it is useful to merge tables aren't files. For
++ * example, the per-workspace and global ref namespace can be implemented as a
++ * merged table of two stacks of file-backed reftables.
++ */
+
+/* A merged table is implements seeking/iterating over a stack of tables. */
+struct reftable_merged_table;
@@ reftable/reftable-stack.h (new)
+#include "reftable-writer.h"
+
+/*
-+ The stack presents an interface to a mutable sequence of reftables.
++ * The stack presents an interface to a mutable sequence of reftables.
+
-+ A stack can be mutated by pushing a table to the top of the stack.
++ * A stack can be mutated by pushing a table to the top of the stack.
+
-+ The reftable_stack automatically compacts files on disk to ensure good
-+ amortized performance.
-+*/
++ * The reftable_stack automatically compacts files on disk to ensure good
++ * amortized performance.
++ *
++ * For windows and other platforms that cannot have open files as rename
++ * destinations, concurrent access from multiple processes needs the rand()
++ * random seed to be randomized.
++ */
+struct reftable_stack;
+
+/* open a new reftable stack. The tables along with the table list will be
-+ stored in 'dir'. Typically, this should be .git/reftables.
-+*/
++ * stored in 'dir'. Typically, this should be .git/reftables.
++ */
+int reftable_new_stack(struct reftable_stack **dest, const char *dir,
+ struct reftable_write_options config);
+
@@ reftable/reftable-stack.h (new)
+struct reftable_addition;
+
+/*
-+ returns a new transaction to add reftables to the given stack. As a side
-+ effect, the ref database is locked.
-+*/
++ * returns a new transaction to add reftables to the given stack. As a side
++ * effect, the ref database is locked.
++ */
+int reftable_stack_new_addition(struct reftable_addition **dest,
+ struct reftable_stack *st);
+
@@ reftable/reftable-stack.h (new)
+int reftable_addition_commit(struct reftable_addition *add);
+
+/* Release all non-committed data from the transaction, and deallocate the
-+ transaction. Releases the lock if held. */
++ * transaction. Releases the lock if held. */
+void reftable_addition_destroy(struct reftable_addition *add);
+
+/* add a new table to the stack. The write_table function must call
-+ reftable_writer_set_limits, add refs and return an error value. */
++ * reftable_writer_set_limits, add refs and return an error value. */
+int reftable_stack_add(struct reftable_stack *st,
+ int (*write_table)(struct reftable_writer *wr,
+ void *write_arg),
+ void *write_arg);
+
+/* returns the merged_table for seeking. This table is valid until the
-+ next write or reload, and should not be closed or deleted.
-+*/
++ * next write or reload, and should not be closed or deleted.
++ */
+struct reftable_merged_table *
+reftable_stack_merged_table(struct reftable_stack *st);
+
@@ reftable/reftable-stack.h (new)
+/* heuristically compact unbalanced table stack. */
+int reftable_stack_auto_compact(struct reftable_stack *st);
+
-+/* convenience function to read a single ref. Returns < 0 for error, 0
-+ for success, and 1 if ref not found. */
++/* convenience function to read a single ref. Returns < 0 for error, 0 for
++ * success, and 1 if ref not found. */
+int reftable_stack_read_ref(struct reftable_stack *st, const char *refname,
+ struct reftable_ref_record *ref);
+
-+/* convenience function to read a single log. Returns < 0 for error, 0
-+ for success, and 1 if ref not found. */
++/* convenience function to read a single log. Returns < 0 for error, 0 for
++ * success, and 1 if ref not found. */
+int reftable_stack_read_log(struct reftable_stack *st, const char *refname,
+ struct reftable_log_record *log);
+
@@ reftable/stack.c (new)
+static void format_name(struct strbuf *dest, uint64_t min, uint64_t max)
+{
+ char buf[100];
-+ snprintf(buf, sizeof(buf), "0x%012" PRIx64 "-0x%012" PRIx64, min, max);
++ uint32_t rnd = (uint32_t)rand();
++ snprintf(buf, sizeof(buf), "0x%012" PRIx64 "-0x%012" PRIx64 "-%08x",
++ min, max, rnd);
+ strbuf_reset(dest);
+ strbuf_addstr(dest, buf);
+}
@@ reftable/stack.c (new)
+ int lock_file_fd;
+ struct strbuf lock_file_name;
+ struct reftable_stack *stack;
-+ char **names;
++
+ char **new_tables;
+ int new_tables_len;
+ uint64_t next_update_index;
@@ reftable/stack.c (new)
+ struct strbuf nm = STRBUF_INIT;
+ for (i = 0; i < add->new_tables_len; i++) {
+ strbuf_reset(&nm);
-+ strbuf_addstr(&nm, add->stack->list_file);
++ strbuf_addstr(&nm, add->stack->reftable_dir);
+ strbuf_addstr(&nm, "/");
+ strbuf_addstr(&nm, add->new_tables[i]);
+ unlink(nm.buf);
@@ reftable/stack.c (new)
+ strbuf_release(&add->lock_file_name);
+ }
+
-+ free_names(add->names);
-+ add->names = NULL;
+ strbuf_release(&nm);
+}
+
@@ reftable/stack.c (new)
+ goto done;
+ }
+
-+ err = reftable_stack_reload(add->stack);
++ /* success, no more state to clean up. */
++ strbuf_release(&add->lock_file_name);
++ for (i = 0; i < add->new_tables_len; i++) {
++ reftable_free(add->new_tables[i]);
++ }
++ reftable_free(add->new_tables);
++ add->new_tables = NULL;
++ add->new_tables_len = 0;
+
++ err = reftable_stack_reload(add->stack);
+done:
+ reftable_addition_close(add);
+ return err;
@@ reftable/stack.c (new)
+ strbuf_addstr(&tab_file_name, "/");
+ strbuf_addbuf(&tab_file_name, &next_name);
+
-+ /* TODO: should check destination out of paranoia */
++ /*
++ On windows, this relies on rand() picking a unique destination name.
++ Maybe we should do retry loop as well?
++ */
+ err = rename(temp_tab_file_name.buf, tab_file_name.buf);
+ if (err < 0) {
+ err = REFTABLE_IO_ERROR;
@@ reftable/stack.c (new)
+
+ format_name(&next_name,
+ reftable_reader_min_update_index(st->readers[first]),
-+ reftable_reader_max_update_index(st->readers[first]));
++ reftable_reader_max_update_index(st->readers[last]));
+
+ strbuf_reset(temp_tab);
+ strbuf_addstr(temp_tab, st->reftable_dir);
@@ reftable/stack.c (new)
+ if (err < 0) {
+ break;
+ }
++
+ if (first == 0 && reftable_ref_record_is_deletion(&ref)) {
+ continue;
+ }
@@ reftable/stack.c (new)
+ strbuf_addbuf(&new_table_path, &new_table_name);
+
+ if (!is_empty_table) {
++ /* retry? */
+ err = rename(temp_tab_file_name.buf, new_table_path.buf);
+ if (err < 0) {
+ err = REFTABLE_IO_ERROR;
@@ reftable/stack_test.c (new)
+ strbuf_release(&path);
+}
+
++static char *get_tmp_template(const char *prefix)
++{
++ const char *tmp = getenv("TMPDIR");
++ static char template[1024];
++ snprintf(template, sizeof(template) - 1, "%s/%s.XXXXXX",
++ tmp ? tmp : "/tmp", prefix);
++ return template;
++}
++
+static void test_read_file(void)
+{
-+ char fn[256] = "/tmp/stack.test_read_file.XXXXXX";
++ char *fn = get_tmp_template(__FUNCTION__);
+ int fd = mkstemp(fn);
+ char out[1024] = "line1\n\nline2\nline3";
+ int n, err;
@@ reftable/stack_test.c (new)
+
+static void test_reftable_stack_add_one(void)
+{
-+ char dir[256] = "/tmp/stack_test.XXXXXX";
++ char *dir = get_tmp_template(__FUNCTION__);
+ struct reftable_write_options cfg = { 0 };
+ struct reftable_stack *st = NULL;
+ int err;
+ struct reftable_ref_record ref = {
+ .refname = "HEAD",
+ .update_index = 1,
-+ .target = "master",
++ .value_type = REFTABLE_REF_SYMREF,
++ .value.symref = "master",
+ };
+ struct reftable_ref_record dest = { NULL };
+
@@ reftable/stack_test.c (new)
+
+ err = reftable_stack_read_ref(st, ref.refname, &dest);
+ EXPECT_ERR(err);
-+ EXPECT(0 == strcmp("master", dest.target));
++ EXPECT(0 == strcmp("master", dest.value.symref));
+
+ reftable_ref_record_release(&dest);
+ reftable_stack_destroy(st);
@@ reftable/stack_test.c (new)
+ struct reftable_write_options cfg = { 0 };
+ struct reftable_stack *st1 = NULL;
+ struct reftable_stack *st2 = NULL;
-+ char dir[256] = "/tmp/stack_test.XXXXXX";
++ char *dir = get_tmp_template(__FUNCTION__);
+ int err;
+ struct reftable_ref_record ref1 = {
+ .refname = "HEAD",
+ .update_index = 1,
-+ .target = "master",
++ .value_type = REFTABLE_REF_SYMREF,
++ .value.symref = "master",
+ };
+ struct reftable_ref_record ref2 = {
+ .refname = "branch2",
+ .update_index = 2,
-+ .target = "master",
++ .value_type = REFTABLE_REF_SYMREF,
++ .value.symref = "master",
+ };
+
+ EXPECT(mkdtemp(dir));
+
++ /* simulate multi-process access to the same stack
++ by creating two stacks for the same directory.
++ */
+ err = reftable_new_stack(&st1, dir, cfg);
+ EXPECT_ERR(err);
+
@@ reftable/stack_test.c (new)
+
+static void test_reftable_stack_transaction_api(void)
+{
-+ char dir[256] = "/tmp/stack_test.XXXXXX";
++ char *dir = get_tmp_template(__FUNCTION__);
+ struct reftable_write_options cfg = { 0 };
+ struct reftable_stack *st = NULL;
+ int err;
@@ reftable/stack_test.c (new)
+ struct reftable_ref_record ref = {
+ .refname = "HEAD",
+ .update_index = 1,
-+ .target = "master",
++ .value_type = REFTABLE_REF_SYMREF,
++ .value.symref = "master",
+ };
+ struct reftable_ref_record dest = { NULL };
+
@@ reftable/stack_test.c (new)
+
+ err = reftable_stack_read_ref(st, ref.refname, &dest);
+ EXPECT_ERR(err);
-+ EXPECT(0 == strcmp("master", dest.target));
++ EXPECT(REFTABLE_REF_SYMREF == dest.value_type);
++ EXPECT(0 == strcmp("master", dest.value.symref));
+
+ reftable_ref_record_release(&dest);
+ reftable_stack_destroy(st);
@@ reftable/stack_test.c (new)
+ struct reftable_write_options cfg = { 0 };
+ struct reftable_stack *st = NULL;
+ int err;
-+ char dir[256] = "/tmp/stack_test.XXXXXX";
++ char *dir = get_tmp_template(__FUNCTION__);
+ int i;
+ struct reftable_ref_record ref = {
+ .refname = "a/b",
+ .update_index = 1,
-+ .target = "master",
++ .value_type = REFTABLE_REF_SYMREF,
++ .value.symref = "master",
+ };
+ char *additions[] = { "a", "a/b/c" };
+
@@ reftable/stack_test.c (new)
+ struct reftable_ref_record ref = {
+ .refname = additions[i],
+ .update_index = 1,
-+ .target = "master",
++ .value_type = REFTABLE_REF_SYMREF,
++ .value.symref = "master",
+ };
+
+ err = reftable_stack_add(st, &write_test_ref, &ref);
@@ reftable/stack_test.c (new)
+
+static void test_reftable_stack_update_index_check(void)
+{
-+ char dir[256] = "/tmp/stack_test.XXXXXX";
++ char *dir = get_tmp_template(__FUNCTION__);
+ struct reftable_write_options cfg = { 0 };
+ struct reftable_stack *st = NULL;
+ int err;
+ struct reftable_ref_record ref1 = {
+ .refname = "name1",
+ .update_index = 1,
-+ .target = "master",
++ .value_type = REFTABLE_REF_SYMREF,
++ .value.symref = "master",
+ };
+ struct reftable_ref_record ref2 = {
+ .refname = "name2",
+ .update_index = 1,
-+ .target = "master",
++ .value_type = REFTABLE_REF_SYMREF,
++ .value.symref = "master",
+ };
+ EXPECT(mkdtemp(dir));
+
@@ reftable/stack_test.c (new)
+
+static void test_reftable_stack_lock_failure(void)
+{
-+ char dir[256] = "/tmp/stack_test.XXXXXX";
++ char *dir = get_tmp_template(__FUNCTION__);
+ struct reftable_write_options cfg = { 0 };
+ struct reftable_stack *st = NULL;
+ int err, i;
@@ reftable/stack_test.c (new)
+ .exact_log_message = 1,
+ };
+ struct reftable_stack *st = NULL;
-+ char dir[256] = "/tmp/stack_test.XXXXXX";
++ char *dir = get_tmp_template(__FUNCTION__);
+ struct reftable_ref_record refs[2] = { { NULL } };
+ struct reftable_log_record logs[2] = { { NULL } };
+ int N = ARRAY_SIZE(refs);
@@ reftable/stack_test.c (new)
+ char buf[256];
+ snprintf(buf, sizeof(buf), "branch%02d", i);
+ refs[i].refname = xstrdup(buf);
-+ refs[i].value = reftable_malloc(SHA1_SIZE);
+ refs[i].update_index = i + 1;
-+ set_test_hash(refs[i].value, i);
++ refs[i].value_type = REFTABLE_REF_VAL1;
++ refs[i].value.val1 = reftable_malloc(SHA1_SIZE);
++ set_test_hash(refs[i].value.val1, i);
+
+ logs[i].refname = xstrdup(buf);
+ logs[i].update_index = N + i + 1;
@@ reftable/stack_test.c (new)
+ 0,
+ };
+ struct reftable_stack *st = NULL;
-+ char dir[256] = "/tmp/stack_test.XXXXXX";
++ char *dir = get_tmp_template(__FUNCTION__);
+
+ uint8_t h1[SHA1_SIZE] = { 0x01 }, h2[SHA1_SIZE] = { 0x02 };
+
@@ reftable/stack_test.c (new)
+static void test_reftable_stack_tombstone(void)
+{
+ int i = 0;
-+ char dir[256] = "/tmp/stack_test.XXXXXX";
++ char *dir = get_tmp_template(__FUNCTION__);
+ struct reftable_write_options cfg = { 0 };
+ struct reftable_stack *st = NULL;
+ int err;
@@ reftable/stack_test.c (new)
+ refs[i].refname = xstrdup(buf);
+ refs[i].update_index = i + 1;
+ if (i % 2 == 0) {
-+ refs[i].value = reftable_malloc(SHA1_SIZE);
-+ set_test_hash(refs[i].value, i);
++ refs[i].value_type = REFTABLE_REF_VAL1;
++ refs[i].value.val1 = reftable_malloc(SHA1_SIZE);
++ set_test_hash(refs[i].value.val1, i);
+ }
+ logs[i].refname = xstrdup(buf);
+ /* update_index is part of the key. */
@@ reftable/stack_test.c (new)
+
+static void test_reftable_stack_hash_id(void)
+{
-+ char dir[256] = "/tmp/stack_test.XXXXXX";
++ char *dir = get_tmp_template(__FUNCTION__);
+ struct reftable_write_options cfg = { 0 };
+ struct reftable_stack *st = NULL;
+ int err;
+
+ struct reftable_ref_record ref = {
+ .refname = "master",
-+ .target = "target",
++ .value_type = REFTABLE_REF_SYMREF,
++ .value.symref = "target",
+ .update_index = 1,
+ };
+ struct reftable_write_options cfg32 = { .hash_id = SHA256_ID };
@@ reftable/stack_test.c (new)
+ err = reftable_stack_read_ref(st_default, "master", &dest);
+ EXPECT_ERR(err);
+
-+ EXPECT(!strcmp(dest.target, ref.target));
++ EXPECT(reftable_ref_record_equal(&ref, &dest, SHA1_SIZE));
+ reftable_ref_record_release(&dest);
+ reftable_stack_destroy(st);
+ reftable_stack_destroy(st_default);
@@ reftable/stack_test.c (new)
+
+static void test_sizes_to_segments_empty(void)
+{
-+ uint64_t sizes[0];
-+
+ int seglen = 0;
-+ struct segment *segs =
-+ sizes_to_segments(&seglen, sizes, ARRAY_SIZE(sizes));
++ struct segment *segs = sizes_to_segments(&seglen, NULL, 0);
+ EXPECT(seglen == 0);
+ reftable_free(segs);
+}
@@ reftable/stack_test.c (new)
+
+static void test_reflog_expire(void)
+{
-+ char dir[256] = "/tmp/stack.test_reflog_expire.XXXXXX";
++ char *dir = get_tmp_template(__FUNCTION__);
+ struct reftable_write_options cfg = { 0 };
+ struct reftable_stack *st = NULL;
+ struct reftable_log_record logs[20] = { { NULL } };
@@ reftable/stack_test.c (new)
+ struct reftable_write_options cfg = { 0 };
+ struct reftable_stack *st = NULL;
+ int err;
-+ char dir[256] = "/tmp/stack_test.XXXXXX";
++ char *dir = get_tmp_template(__FUNCTION__);
+ struct reftable_stack *st2 = NULL;
+
+ EXPECT(mkdtemp(dir));
@@ reftable/stack_test.c (new)
+{
+ struct reftable_write_options cfg = { 0 };
+ struct reftable_stack *st = NULL;
-+ char dir[256] = "/tmp/stack_test.XXXXXX";
++ char *dir = get_tmp_template(__FUNCTION__);
+ int err, i;
+ int N = 100;
+ EXPECT(mkdtemp(dir));
@@ reftable/stack_test.c (new)
+ struct reftable_ref_record ref = {
+ .refname = name,
+ .update_index = reftable_stack_next_update_index(st),
-+ .target = "master",
++ .value_type = REFTABLE_REF_SYMREF,
++ .value.symref = "master",
+ };
+ snprintf(name, sizeof(name), "branch%04d", i);
+
@@ reftable/stack_test.c (new)
+
+int stack_test_main(int argc, const char *argv[])
+{
-+ test_reftable_stack_uptodate();
-+ test_reftable_stack_transaction_api();
-+ test_reftable_stack_hash_id();
-+ test_sizes_to_segments_all_equal();
-+ test_reftable_stack_auto_compaction();
-+ test_reftable_stack_validate_refname();
-+ test_reftable_stack_update_index_check();
-+ test_reftable_stack_lock_failure();
-+ test_reftable_stack_log_normalize();
-+ test_reftable_stack_tombstone();
-+ test_reftable_stack_add_one();
-+ test_empty_add();
-+ test_reflog_expire();
-+ test_suggest_compaction_segment();
-+ test_suggest_compaction_segment_nothing();
-+ test_sizes_to_segments();
-+ test_sizes_to_segments_empty();
-+ test_log2();
-+ test_parse_names();
-+ test_read_file();
-+ test_names_equal();
-+ test_reftable_stack_add();
++ RUN_TEST(test_reftable_stack_uptodate);
++ RUN_TEST(test_reftable_stack_transaction_api);
++ RUN_TEST(test_reftable_stack_hash_id);
++ RUN_TEST(test_sizes_to_segments_all_equal);
++ RUN_TEST(test_reftable_stack_auto_compaction);
++ RUN_TEST(test_reftable_stack_validate_refname);
++ RUN_TEST(test_reftable_stack_update_index_check);
++ RUN_TEST(test_reftable_stack_lock_failure);
++ RUN_TEST(test_reftable_stack_log_normalize);
++ RUN_TEST(test_reftable_stack_tombstone);
++ RUN_TEST(test_reftable_stack_add_one);
++ RUN_TEST(test_empty_add);
++ RUN_TEST(test_reflog_expire);
++ RUN_TEST(test_suggest_compaction_segment);
++ RUN_TEST(test_suggest_compaction_segment_nothing);
++ RUN_TEST(test_sizes_to_segments);
++ RUN_TEST(test_sizes_to_segments_empty);
++ RUN_TEST(test_log2);
++ RUN_TEST(test_parse_names);
++ RUN_TEST(test_read_file);
++ RUN_TEST(test_names_equal);
++ RUN_TEST(test_reftable_stack_add);
+ return 0;
+}
14: a590865a700 ! 13: d57023d9f13 Reftable support for git-core
@@ Commit message
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Co-authored-by: Jeff King <peff@peff.net>
+ ## Documentation/config/extensions.txt ##
+@@ Documentation/config/extensions.txt: extensions.objectFormat::
+ Note that this setting should only be set by linkgit:git-init[1] or
+ linkgit:git-clone[1]. Trying to change it after initialization will not
+ work and will produce hard-to-diagnose issues.
+++
++extensions.refStorage::
++ Specify the ref storage mechanism to use. The acceptable values are `files` and
++ `reftable`. If not specified, `files` is assumed. It is an error to specify
++ this key unless `core.repositoryFormatVersion` is 1.
+++
++Note that this setting should only be set by linkgit:git-init[1] or
++linkgit:git-clone[1]. Trying to change it after initialization will not
++work and will produce hard-to-diagnose issues.
+
## Documentation/technical/repository-version.txt ##
@@ Documentation/technical/repository-version.txt: If set, by default "git config" reads from both "config" and
multiple working directory mode, "config" file is shared while
@@ refs/reftable-backend.c (new)
+ continue;
+
+ ri->base.flags = 0;
-+ if (ri->ref.value != NULL) {
-+ hashcpy(ri->oid.hash, ri->ref.value);
-+ } else if (ri->ref.target != NULL) {
++ switch (ri->ref.value_type) {
++ case REFTABLE_REF_VAL1:
++ hashcpy(ri->oid.hash, ri->ref.value.val1);
++ break;
++ case REFTABLE_REF_VAL2:
++ hashcpy(ri->oid.hash, ri->ref.value.val2.value);
++ break;
++ case REFTABLE_REF_SYMREF: {
+ int out_flags = 0;
+ const char *resolved = refs_resolve_ref_unsafe(
+ ri->ref_store, ri->ref.refname,
@@ refs/reftable-backend.c (new)
+ (ri->base.flags & REF_ISBROKEN)) {
+ continue;
+ }
++ break;
++ }
++ default:
++ abort();
+ }
+
+ ri->base.oid = &ri->oid;
@@ refs/reftable-backend.c (new)
+{
+ struct git_reftable_iterator *ri =
+ (struct git_reftable_iterator *)ref_iterator;
-+ if (ri->ref.target_value != NULL) {
-+ hashcpy(peeled->hash, ri->ref.target_value);
++ if (ri->ref.value_type == REFTABLE_REF_VAL2) {
++ hashcpy(peeled->hash, ri->ref.value.val2.target_value);
+ return 0;
+ }
+
@@ refs/reftable-backend.c (new)
+
+ int peel_error = peel_object(&u->new_oid, &peeled);
+ ref.refname = (char *)u->refname;
-+
-+ if (!is_null_oid(&u->new_oid)) {
-+ ref.value = u->new_oid.hash;
-+ }
+ ref.update_index = ts;
++
+ if (!peel_error) {
-+ ref.target_value = peeled.hash;
++ ref.value_type = REFTABLE_REF_VAL2;
++ ref.value.val2.target_value = peeled.hash;
++ ref.value.val2.value = u->new_oid.hash;
++ } else if (!is_null_oid(&u->new_oid)) {
++ ref.value_type = REFTABLE_REF_VAL1;
++ ref.value.val1 = u->new_oid.hash;
+ }
+
+ err = reftable_writer_add_ref(writer, &ref);
@@ refs/reftable-backend.c (new)
+ for (i = 0; i < arg->refnames->nr; i++) {
+ struct reftable_ref_record ref = {
+ .refname = (char *)arg->refnames->items[i].string,
++ .value_type = REFTABLE_REF_DELETION,
+ .update_index = ts,
+ };
+ err = reftable_writer_add_ref(writer, &ref);
@@ refs/reftable-backend.c (new)
+
+ if (reftable_stack_read_ref(arg->stack, log.refname,
+ ¤t) == 0) {
-+ log.old_hash = current.value;
++ log.old_hash = reftable_ref_record_val1(¤t);
+ }
+ err = reftable_writer_add_log(writer, &log);
+ log.old_hash = NULL;
@@ refs/reftable-backend.c (new)
+
+ struct reftable_ref_record ref = {
+ .refname = (char *)create->refname,
-+ .target = (char *)create->target,
++ .value_type = REFTABLE_REF_SYMREF,
++ .value.symref = (char *)create->target,
+ .update_index = ts,
+ };
+ reftable_writer_set_limits(writer, ts, ts);
@@ refs/reftable-backend.c (new)
+ goto done;
+ }
+
-+ free(ref.refname);
-+ ref.refname = strdup(arg->newname);
+ reftable_writer_set_limits(writer, ts, ts);
-+ ref.update_index = ts;
+
+ {
-+ struct reftable_ref_record todo[2] = { { NULL } };
-+ todo[0].refname = (char *)arg->oldname;
-+ todo[0].update_index = ts;
-+ /* leave todo[0] empty */
-+ todo[1] = ref;
++ struct reftable_ref_record todo[2] = {
++ {
++ .refname = (char *)arg->oldname,
++ .update_index = ts,
++ .value_type = REFTABLE_REF_DELETION,
++ },
++ ref,
++ };
+ todo[1].update_index = ts;
++ free(todo[1].refname);
++ todo[1].refname = strdup(arg->newname);
+
+ err = reftable_writer_add_refs(writer, todo, 2);
+ if (err < 0) {
@@ refs/reftable-backend.c (new)
+ }
+ }
+
-+ if (ref.value != NULL) {
++ if (reftable_ref_record_val1(&ref)) {
++ uint8_t *val1 = reftable_ref_record_val1(&ref);
+ struct reftable_log_record todo[2] = { { NULL } };
+ fill_reftable_log_record(&todo[0]);
+ fill_reftable_log_record(&todo[1]);
@@ refs/reftable-backend.c (new)
+ todo[0].refname = (char *)arg->oldname;
+ todo[0].update_index = ts;
+ todo[0].message = (char *)arg->logmsg;
-+ todo[0].old_hash = ref.value;
++ todo[0].old_hash = val1;
+ todo[0].new_hash = NULL;
+
+ todo[1].refname = (char *)arg->newname;
+ todo[1].update_index = ts;
+ todo[1].old_hash = NULL;
-+ todo[1].new_hash = ref.value;
++ todo[1].new_hash = val1;
+ todo[1].message = (char *)arg->logmsg;
+
+ err = reftable_writer_add_logs(writer, todo, 2);
@@ refs/reftable-backend.c (new)
+ err = -1;
+ goto done;
+ }
-+ if (ref.target != NULL) {
++
++ if (ref.value_type == REFTABLE_REF_SYMREF) {
+ strbuf_reset(referent);
-+ strbuf_addstr(referent, ref.target);
++ strbuf_addstr(referent, ref.value.symref);
+ *type |= REF_ISSYMREF;
-+ } else if (ref.value != NULL) {
-+ hashcpy(oid->hash, ref.value);
++ } else if (reftable_ref_record_val1(&ref) != NULL) {
++ hashcpy(oid->hash, reftable_ref_record_val1(&ref));
+ } else {
+ *type |= REF_ISBROKEN;
+ errno = EINVAL;
15: 57626bfe2d4 = 14: 9df5bc69f97 git-prompt: prepare for reftable refs backend
16: 6229da992e4 ! 15: 4076ef5d20b Add "test-tool dump-reftable" command.
@@ reftable/dump.c: static int dump_table(const char *tablename)
reftable_reader_free(r);
return 0;
-@@ reftable/dump.c: static int dump_stack(const char *stackdir)
+@@ reftable/dump.c: static int dump_table(const char *tablename)
+ static int compact_stack(const char *stackdir)
{
struct reftable_stack *stack = NULL;
- struct reftable_write_options cfg = {};
+- struct reftable_write_options cfg = {};
++ struct reftable_write_options cfg = { 0 };
+
+ int err = reftable_new_stack(&stack, stackdir, cfg);
+ if (err < 0)
+@@ reftable/dump.c: static int compact_stack(const char *stackdir)
+ static int dump_stack(const char *stackdir)
+ {
+ struct reftable_stack *stack = NULL;
+- struct reftable_write_options cfg = {};
- struct reftable_iterator it = { 0 };
- struct reftable_ref_record ref = { 0 };
- struct reftable_log_record log = { 0 };
++ struct reftable_write_options cfg = { 0 };
+ struct reftable_iterator it = { NULL };
+ struct reftable_ref_record ref = { NULL };
+ struct reftable_log_record log = { NULL };
@@ reftable/dump.c: static int dump_stack(const char *stackdir)
reftable_stack_destroy(stack);
return 0;
+@@ reftable/dump.c: static void print_help(void)
+ int reftable_dump_main(int argc, char *const *argv)
+ {
+ int err = 0;
+- int opt;
+ int opt_dump_table = 0;
+ int opt_dump_stack = 0;
+ int opt_compact = 0;
+- const char *arg = NULL;
+- while ((opt = getopt(argc, argv, "2chts")) != -1) {
+- switch (opt) {
+- case '2':
+- hash_id = 0x73323536;
++ const char *arg = NULL, *argv0 = argv[0];
++
++ for (; argc > 1; argv++, argc--)
++ if (*argv[1] != '-')
+ break;
+- case 't':
++ else if (!strcmp("-2", argv[1]))
++ hash_id = 0x73323536;
++ else if (!strcmp("-t", argv[1]))
+ opt_dump_table = 1;
+- break;
+- case 's':
++ else if (!strcmp("-s", argv[1]))
+ opt_dump_stack = 1;
+- break;
+- case 'c':
++ else if (!strcmp("-c", argv[1]))
+ opt_compact = 1;
+- break;
+- case '?':
+- case 'h':
++ else if (!strcmp("-?", argv[1]) || !strcmp("-h", argv[1])) {
+ print_help();
+ return 2;
+- break;
+ }
+- }
+
+- if (argv[optind] == NULL) {
++ if (argc != 2) {
+ fprintf(stderr, "need argument\n");
+ print_help();
+ return 2;
+ }
+
+- arg = argv[optind];
++ arg = argv[1];
+
+ if (opt_dump_table) {
+ err = dump_table(arg);
+@@ reftable/dump.c: int reftable_dump_main(int argc, char *const *argv)
+ }
+
+ if (err < 0) {
+- fprintf(stderr, "%s: %s: %s\n", argv[0], arg,
++ fprintf(stderr, "%s: %s: %s\n", argv0, arg,
+ reftable_error_str(err));
+ return 1;
+ }
## t/helper/test-reftable.c ##
@@ t/helper/test-reftable.c: int cmd__reftable(int argc, const char **argv)
--
gitgitgadget
next prev parent reply other threads:[~2020-12-09 14:04 UTC|newest]
Thread overview: 251+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-09-16 19:10 [PATCH 00/13] reftable library Han-Wen Nienhuys via GitGitGadget
2020-09-16 19:10 ` [PATCH 01/13] reftable: add LICENSE Han-Wen Nienhuys via GitGitGadget
2020-09-16 19:10 ` [PATCH 02/13] reftable: define the public API Han-Wen Nienhuys via GitGitGadget
2020-09-16 19:10 ` [PATCH 03/13] vcxproj: adjust for the reftable changes Johannes Schindelin via GitGitGadget
2020-09-16 19:10 ` [PATCH 04/13] reftable: add a barebones unittest framework Han-Wen Nienhuys via GitGitGadget
2020-09-16 19:10 ` [PATCH 05/13] reftable: utility functions Han-Wen Nienhuys via GitGitGadget
2020-09-16 19:10 ` [PATCH 06/13] reftable: (de)serialization for the polymorphic record type Han-Wen Nienhuys via GitGitGadget
2020-09-20 1:00 ` Junio C Hamano
2020-09-21 13:13 ` Han-Wen Nienhuys
2020-09-24 7:21 ` Jeff King
2020-09-24 7:31 ` Jeff King
2020-09-24 17:22 ` Junio C Hamano
2020-09-16 19:10 ` [PATCH 07/13] reftable: reading/writing blocks Han-Wen Nienhuys via GitGitGadget
2020-09-16 19:10 ` [PATCH 08/13] reftable: a generic binary tree implementation Han-Wen Nienhuys via GitGitGadget
2020-09-16 19:10 ` [PATCH 09/13] reftable: write reftable files Han-Wen Nienhuys via GitGitGadget
2020-09-16 19:10 ` [PATCH 10/13] reftable: read " Han-Wen Nienhuys via GitGitGadget
2020-09-16 19:10 ` [PATCH 11/13] reftable: file level tests Han-Wen Nienhuys via GitGitGadget
2020-09-16 19:10 ` [PATCH 12/13] reftable: rest of library Han-Wen Nienhuys via GitGitGadget
2020-09-16 19:10 ` [PATCH 13/13] reftable: "test-tool dump-reftable" command Han-Wen Nienhuys via GitGitGadget
2020-10-01 16:10 ` [PATCH v2 00/13] reftable library Han-Wen Nienhuys via GitGitGadget
2020-10-01 16:10 ` [PATCH v2 01/13] reftable: add LICENSE Han-Wen Nienhuys via GitGitGadget
2020-10-02 3:18 ` Jonathan Nieder
2020-10-01 16:10 ` [PATCH v2 02/13] reftable: define the public API Han-Wen Nienhuys via GitGitGadget
2020-10-02 3:58 ` Jonathan Nieder
2020-10-09 21:13 ` Emily Shaffer
2020-10-10 17:03 ` Han-Wen Nienhuys
2020-11-30 14:44 ` Han-Wen Nienhuys
2020-10-10 13:43 ` Han-Wen Nienhuys
2020-10-12 16:57 ` Jonathan Nieder
2020-11-30 14:55 ` Han-Wen Nienhuys
2020-10-08 1:41 ` Jonathan Tan
2020-10-10 16:57 ` Han-Wen Nienhuys
2020-10-01 16:10 ` [PATCH v2 03/13] vcxproj: adjust for the reftable changes Johannes Schindelin via GitGitGadget
2020-10-02 4:02 ` Jonathan Nieder
2020-10-02 11:43 ` Johannes Schindelin
2020-10-01 16:10 ` [PATCH v2 04/13] reftable: add a barebones unittest framework Han-Wen Nienhuys via GitGitGadget
2020-10-02 4:05 ` Jonathan Nieder
2020-10-08 1:45 ` Jonathan Tan
2020-10-08 22:31 ` Josh Steadmon
2020-10-01 16:10 ` [PATCH v2 05/13] reftable: utility functions Han-Wen Nienhuys via GitGitGadget
2020-10-02 4:12 ` Jonathan Nieder
2020-10-10 17:32 ` Han-Wen Nienhuys
2020-10-12 15:25 ` Jonathan Nieder
2020-10-12 17:05 ` Patrick Steinhardt
2020-10-12 17:45 ` Jonathan Nieder
2020-10-13 12:12 ` Johannes Schindelin
2020-10-13 15:47 ` Junio C Hamano
2020-10-15 11:46 ` Johannes Schindelin
2020-10-15 16:23 ` Junio C Hamano
2020-10-15 19:39 ` Johannes Schindelin
2020-10-16 9:15 ` Patrick Steinhardt
2020-10-02 14:01 ` Johannes Schindelin
2020-10-02 20:47 ` Junio C Hamano
2020-10-03 8:07 ` Johannes Schindelin
2020-10-08 1:48 ` Jonathan Tan
2020-10-10 17:28 ` Han-Wen Nienhuys
2020-10-11 10:52 ` Johannes Schindelin
2020-10-12 15:19 ` Jonathan Nieder
2020-10-12 18:44 ` Johannes Schindelin
2020-10-12 19:41 ` Jonathan Nieder
2020-10-12 20:27 ` Johannes Schindelin
2020-10-12 16:42 ` Junio C Hamano
2020-10-12 19:01 ` Johannes Schindelin
2020-10-23 9:13 ` Ævar Arnfjörð Bjarmason
2020-10-23 17:36 ` Junio C Hamano
2020-10-01 16:10 ` [PATCH v2 06/13] reftable: (de)serialization for the polymorphic record type Han-Wen Nienhuys via GitGitGadget
2020-10-01 19:23 ` Junio C Hamano
2020-10-01 19:59 ` Ramsay Jones
2020-10-01 16:10 ` [PATCH v2 07/13] reftable: reading/writing blocks Han-Wen Nienhuys via GitGitGadget
2020-10-01 16:10 ` [PATCH v2 08/13] reftable: a generic binary tree implementation Han-Wen Nienhuys via GitGitGadget
2020-10-01 16:10 ` [PATCH v2 09/13] reftable: write reftable files Han-Wen Nienhuys via GitGitGadget
2020-10-01 16:11 ` [PATCH v2 10/13] reftable: read " Han-Wen Nienhuys via GitGitGadget
2020-10-01 16:11 ` [PATCH v2 11/13] reftable: file level tests Han-Wen Nienhuys via GitGitGadget
2020-10-01 16:11 ` [PATCH v2 12/13] reftable: rest of library Han-Wen Nienhuys via GitGitGadget
2020-10-02 13:57 ` Johannes Schindelin
2020-10-02 17:08 ` Junio C Hamano
2020-10-04 18:39 ` Johannes Schindelin
2020-10-01 16:11 ` [PATCH v2 13/13] reftable: "test-tool dump-reftable" command Han-Wen Nienhuys via GitGitGadget
2020-11-26 19:42 ` [PATCH v3 00/16] reftable library Han-Wen Nienhuys via GitGitGadget
2020-11-26 19:42 ` [PATCH v3 01/16] move sleep_millisec to git-compat-util.h Han-Wen Nienhuys via GitGitGadget
2020-11-26 19:42 ` [PATCH v3 02/16] init-db: set the_repository->hash_algo early on Han-Wen Nienhuys via GitGitGadget
2020-11-27 10:22 ` Ævar Arnfjörð Bjarmason
2020-11-26 19:42 ` [PATCH v3 03/16] reftable: add LICENSE Han-Wen Nienhuys via GitGitGadget
2020-11-27 10:23 ` Ævar Arnfjörð Bjarmason
2020-11-30 11:26 ` Han-Wen Nienhuys
2020-11-30 20:25 ` Han-Wen Nienhuys
2020-11-30 21:21 ` Felipe Contreras
2020-12-01 9:51 ` Han-Wen Nienhuys
2020-12-01 10:38 ` Felipe Contreras
2020-12-01 11:45 ` Ævar Arnfjörð Bjarmason
2020-12-01 13:34 ` Han-Wen Nienhuys
2020-12-01 23:13 ` Felipe Contreras
2020-12-01 23:03 ` Felipe Contreras
2020-11-26 19:42 ` [PATCH v3 04/16] reftable: add error related functionality Han-Wen Nienhuys via GitGitGadget
2020-11-27 9:13 ` Felipe Contreras
2020-11-27 10:25 ` Ævar Arnfjörð Bjarmason
2020-11-30 11:27 ` Han-Wen Nienhuys
2020-11-26 19:42 ` [PATCH v3 05/16] reftable: utility functions Han-Wen Nienhuys via GitGitGadget
2020-11-27 10:18 ` Felipe Contreras
2020-11-27 10:33 ` Ævar Arnfjörð Bjarmason
2020-11-26 19:42 ` [PATCH v3 06/16] reftable: add blocksource, an abstraction for random access reads Han-Wen Nienhuys via GitGitGadget
2020-11-26 19:42 ` [PATCH v3 07/16] reftable: (de)serialization for the polymorphic record type Han-Wen Nienhuys via GitGitGadget
2020-11-26 19:42 ` [PATCH v3 08/16] reftable: reading/writing blocks Han-Wen Nienhuys via GitGitGadget
2020-11-26 19:42 ` [PATCH v3 09/16] reftable: a generic binary tree implementation Han-Wen Nienhuys via GitGitGadget
2020-11-26 19:42 ` [PATCH v3 10/16] reftable: write reftable files Han-Wen Nienhuys via GitGitGadget
2020-11-26 19:42 ` [PATCH v3 11/16] reftable: read " Han-Wen Nienhuys via GitGitGadget
2020-11-26 19:42 ` [PATCH v3 12/16] reftable: reftable file level tests Han-Wen Nienhuys via GitGitGadget
2020-11-26 19:42 ` [PATCH v3 13/16] reftable: rest of library Han-Wen Nienhuys via GitGitGadget
2020-11-26 19:42 ` [PATCH v3 14/16] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-11-27 10:59 ` Ævar Arnfjörð Bjarmason
2020-11-26 19:42 ` [PATCH v3 15/16] git-prompt: prepare for reftable refs backend SZEDER Gábor via GitGitGadget
2020-11-26 19:42 ` [PATCH v3 16/16] Add "test-tool dump-reftable" command Han-Wen Nienhuys via GitGitGadget
2020-12-09 14:00 ` Han-Wen Nienhuys via GitGitGadget [this message]
2020-12-09 14:00 ` [PATCH v4 01/15] init-db: set the_repository->hash_algo early on Han-Wen Nienhuys via GitGitGadget
2020-12-09 14:00 ` [PATCH v4 02/15] reftable: add LICENSE Han-Wen Nienhuys via GitGitGadget
2020-12-09 14:00 ` [PATCH v4 03/15] reftable: add error related functionality Han-Wen Nienhuys via GitGitGadget
2020-12-09 14:00 ` [PATCH v4 04/15] reftable: utility functions Han-Wen Nienhuys via GitGitGadget
2020-12-09 14:00 ` [PATCH v4 05/15] reftable: add blocksource, an abstraction for random access reads Han-Wen Nienhuys via GitGitGadget
2020-12-09 14:00 ` [PATCH v4 06/15] reftable: (de)serialization for the polymorphic record type Han-Wen Nienhuys via GitGitGadget
2020-12-09 14:00 ` [PATCH v4 07/15] reftable: reading/writing blocks Han-Wen Nienhuys via GitGitGadget
2020-12-09 14:00 ` [PATCH v4 08/15] reftable: a generic binary tree implementation Han-Wen Nienhuys via GitGitGadget
2020-12-09 14:00 ` [PATCH v4 09/15] reftable: write reftable files Han-Wen Nienhuys via GitGitGadget
2020-12-09 14:00 ` [PATCH v4 10/15] reftable: read " Han-Wen Nienhuys via GitGitGadget
2020-12-09 14:00 ` [PATCH v4 11/15] reftable: reftable file level tests Han-Wen Nienhuys via GitGitGadget
2020-12-09 14:00 ` [PATCH v4 12/15] reftable: rest of library Han-Wen Nienhuys via GitGitGadget
2020-12-09 14:00 ` [PATCH v4 13/15] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2021-01-21 15:55 ` Ævar Arnfjörð Bjarmason
2021-01-21 16:14 ` Han-Wen Nienhuys
2021-01-21 16:21 ` Han-Wen Nienhuys
2021-01-26 13:44 ` Ævar Arnfjörð Bjarmason
2021-04-23 10:22 ` Han-Wen Nienhuys
2021-04-26 13:23 ` Ævar Arnfjörð Bjarmason
2021-04-26 16:17 ` Han-Wen Nienhuys
2021-04-28 16:32 ` Ævar Arnfjörð Bjarmason
2021-04-28 17:40 ` Han-Wen Nienhuys
2021-02-22 0:41 ` [PATCH] refs: introduce API function to write invalid null ref Stefan Beller
2021-02-22 1:20 ` Eric Sunshine
2021-02-22 3:09 ` Eric Sunshine
2021-02-22 18:38 ` Han-Wen Nienhuys
2020-12-09 14:00 ` [PATCH v4 14/15] git-prompt: prepare for reftable refs backend SZEDER Gábor via GitGitGadget
2020-12-09 14:00 ` [PATCH v4 15/15] Add "test-tool dump-reftable" command Han-Wen Nienhuys via GitGitGadget
2021-03-12 20:19 ` [PATCH v5 00/15] reftable library Han-Wen Nienhuys via GitGitGadget
2021-03-12 20:19 ` [PATCH v5 01/15] init-db: set the_repository->hash_algo early on Han-Wen Nienhuys via GitGitGadget
2021-03-12 20:19 ` [PATCH v5 02/15] reftable: add LICENSE Han-Wen Nienhuys via GitGitGadget
2021-03-12 20:19 ` [PATCH v5 03/15] reftable: add error related functionality Han-Wen Nienhuys via GitGitGadget
2021-03-12 20:19 ` [PATCH v5 04/15] reftable: utility functions Han-Wen Nienhuys via GitGitGadget
2021-03-12 20:19 ` [PATCH v5 05/15] reftable: add blocksource, an abstraction for random access reads Han-Wen Nienhuys via GitGitGadget
2021-03-12 20:19 ` [PATCH v5 06/15] reftable: (de)serialization for the polymorphic record type Han-Wen Nienhuys via GitGitGadget
2021-03-12 20:19 ` [PATCH v5 07/15] reftable: reading/writing blocks Han-Wen Nienhuys via GitGitGadget
2021-03-12 20:19 ` [PATCH v5 08/15] reftable: a generic binary tree implementation Han-Wen Nienhuys via GitGitGadget
2021-03-12 20:19 ` [PATCH v5 09/15] reftable: write reftable files Han-Wen Nienhuys via GitGitGadget
2021-03-12 20:19 ` [PATCH v5 10/15] reftable: read " Han-Wen Nienhuys via GitGitGadget
2021-03-12 20:19 ` [PATCH v5 11/15] reftable: reftable file level tests Han-Wen Nienhuys via GitGitGadget
2021-03-12 20:19 ` [PATCH v5 12/15] reftable: rest of library Han-Wen Nienhuys via GitGitGadget
2021-03-12 20:19 ` [PATCH v5 13/15] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2021-03-23 11:40 ` Derrick Stolee
2021-03-23 12:20 ` Ævar Arnfjörð Bjarmason
2021-03-23 20:14 ` Junio C Hamano
2021-03-23 20:12 ` Junio C Hamano
2021-03-12 20:19 ` [PATCH v5 14/15] git-prompt: prepare for reftable refs backend SZEDER Gábor via GitGitGadget
2021-03-12 20:19 ` [PATCH v5 15/15] Add "test-tool dump-reftable" command Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 00/20] reftable library Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 01/20] init-db: set the_repository->hash_algo early on Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 02/20] reftable: add LICENSE Han-Wen Nienhuys via GitGitGadget
2021-04-13 7:28 ` Ævar Arnfjörð Bjarmason
2021-04-13 10:50 ` Han-Wen Nienhuys
2021-04-13 13:41 ` Ævar Arnfjörð Bjarmason
2021-04-12 19:25 ` [PATCH v6 03/20] reftable: add error related functionality Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 04/20] reftable: utility functions Han-Wen Nienhuys via GitGitGadget
2021-04-13 8:02 ` Ævar Arnfjörð Bjarmason
2021-04-13 10:58 ` Han-Wen Nienhuys
2021-04-13 12:56 ` Ævar Arnfjörð Bjarmason
2021-04-13 13:14 ` Ævar Arnfjörð Bjarmason
2021-04-15 15:00 ` Han-Wen Nienhuys
2021-04-12 19:25 ` [PATCH v6 05/20] reftable: add blocksource, an abstraction for random access reads Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 06/20] reftable: (de)serialization for the polymorphic record type Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 07/20] reftable: reading/writing blocks Han-Wen Nienhuys via GitGitGadget
2021-04-12 21:40 ` Junio C Hamano
2021-04-13 8:19 ` Ævar Arnfjörð Bjarmason
2021-04-15 8:57 ` Han-Wen Nienhuys
2021-04-12 19:25 ` [PATCH v6 08/20] reftable: a generic binary tree implementation Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 09/20] reftable: write reftable files Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 10/20] reftable: generic interface to tables Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 11/20] reftable: read reftable files Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 12/20] reftable: reftable file level tests Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 13/20] reftable: add a heap-based priority queue for reftable records Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 14/20] reftable: add merged table view Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 15/20] reftable: implement refname validation Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 16/20] reftable: implement stack, a mutable database of reftable files Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 17/20] reftable: add dump utility Han-Wen Nienhuys via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 18/20] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2021-04-13 7:18 ` Ævar Arnfjörð Bjarmason
2021-04-14 16:44 ` Han-Wen Nienhuys
2021-04-16 14:55 ` Ævar Arnfjörð Bjarmason
2021-04-16 18:47 ` Junio C Hamano
2021-04-12 19:25 ` [PATCH v6 19/20] git-prompt: prepare for reftable refs backend SZEDER Gábor via GitGitGadget
2021-04-12 19:25 ` [PATCH v6 20/20] Add "test-tool dump-reftable" command Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 00/28] reftable library Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 01/28] refs: ref_iterator_peel returns boolean, rather than peel_status Han-Wen Nienhuys via GitGitGadget
2021-04-20 18:47 ` Junio C Hamano
2021-04-21 10:15 ` Han-Wen Nienhuys
2021-04-21 23:28 ` Junio C Hamano
2021-04-19 11:37 ` [PATCH v7 02/28] refs: document reflog_expire_fn's flag argument Han-Wen Nienhuys via GitGitGadget
2021-04-20 19:34 ` Junio C Hamano
2021-04-27 15:21 ` Han-Wen Nienhuys
2021-04-19 11:37 ` [PATCH v7 03/28] refs/debug: trace into reflog expiry too Han-Wen Nienhuys via GitGitGadget
2021-04-20 19:41 ` Junio C Hamano
2021-04-22 17:27 ` Han-Wen Nienhuys
2021-04-19 11:37 ` [PATCH v7 04/28] hash.h: provide constants for the hash IDs Han-Wen Nienhuys via GitGitGadget
2021-04-20 19:49 ` Junio C Hamano
2021-04-21 1:04 ` brian m. carlson
2021-04-21 9:43 ` Han-Wen Nienhuys
2021-07-22 8:31 ` Han-Wen Nienhuys
2021-04-19 11:37 ` [PATCH v7 05/28] init-db: set the_repository->hash_algo early on Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 06/28] reftable: add LICENSE Han-Wen Nienhuys via GitGitGadget
2021-04-21 7:48 ` Ævar Arnfjörð Bjarmason
2021-04-21 9:15 ` Han-Wen Nienhuys
2021-04-19 11:37 ` [PATCH v7 07/28] reftable: add error related functionality Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 08/28] reftable: utility functions Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 09/28] reftable: add blocksource, an abstraction for random access reads Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 10/28] reftable: (de)serialization for the polymorphic record type Han-Wen Nienhuys via GitGitGadget
2021-05-04 17:23 ` Andrzej Hunt
2021-05-18 13:12 ` Han-Wen Nienhuys
2021-04-19 11:37 ` [PATCH v7 11/28] Provide zlib's uncompress2 from compat/zlib-compat.c Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 12/28] reftable: reading/writing blocks Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 13/28] reftable: a generic binary tree implementation Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 14/28] reftable: write reftable files Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 15/28] reftable: generic interface to tables Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 16/28] reftable: read reftable files Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 17/28] reftable: reftable file level tests Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 18/28] reftable: add a heap-based priority queue for reftable records Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 19/28] reftable: add merged table view Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 20/28] reftable: implement refname validation Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 21/28] reftable: implement stack, a mutable database of reftable files Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 22/28] reftable: add dump utility Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 23/28] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2021-04-20 22:44 ` Junio C Hamano
2021-04-21 10:19 ` Han-Wen Nienhuys
2021-04-21 23:22 ` Junio C Hamano
2021-05-04 17:24 ` Andrzej Hunt
2021-05-18 13:18 ` Han-Wen Nienhuys
2021-05-18 13:30 ` Han-Wen Nienhuys
2021-04-19 11:37 ` [PATCH v7 24/28] git-prompt: prepare for reftable refs backend SZEDER Gábor via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 25/28] Add "test-tool dump-reftable" command Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 26/28] t1301: document what needs to be done for REFTABLE Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 27/28] t1401,t2011: parameterize HEAD.lock " Han-Wen Nienhuys via GitGitGadget
2021-04-19 11:37 ` [PATCH v7 28/28] t1404: annotate test cases with REFFILES Han-Wen Nienhuys via GitGitGadget
2021-04-21 7:45 ` [PATCH v7 00/28] reftable library Ævar Arnfjörð Bjarmason
2021-04-21 9:52 ` Han-Wen Nienhuys
2021-04-21 11:21 ` Ævar Arnfjörð Bjarmason
2021-04-26 17:59 ` Han-Wen Nienhuys
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=pull.847.v4.git.git.1607522429.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=Johannes.Schindelin@gmx.de \
--cc=avarab@gmail.com \
--cc=emilyshaffer@google.com \
--cc=felipe.contreras@gmail.com \
--cc=git@vger.kernel.org \
--cc=hanwen@google.com \
--cc=hanwenn@gmail.com \
--cc=jonathantanmy@google.com \
--cc=jrnieder@gmail.com \
--cc=peff@peff.net \
--cc=ps@pks.im \
--cc=ramsay@ramsayjones.plus.com \
--cc=steadmon@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).