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>,
"Han-Wen Nienhuys" <hanwenn@gmail.com>
Subject: [PATCH v3 00/16] reftable library
Date: Thu, 26 Nov 2020 19:42:15 +0000 [thread overview]
Message-ID: <pull.847.v3.git.git.1606419752.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.847.v2.git.git.1601568663.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 26 Nov 2020:
* split public API header into multiple headers
* minor adaptions in response to review feedback
* filter out code for standalone compile
* get rid of test framework
Han-Wen Nienhuys (15):
move sleep_millisec to git-compat-util.h
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
.../technical/repository-version.txt | 7 +
Makefile | 46 +-
builtin/clone.c | 5 +-
builtin/init-db.c | 56 +-
builtin/worktree.c | 27 +-
cache.h | 9 +-
config.mak.uname | 2 +-
contrib/buildsystems/Generators/Vcxproj.pm | 11 +-
contrib/completion/git-prompt.sh | 7 +-
git-compat-util.h | 2 +
refs.c | 27 +-
refs.h | 3 +
refs/refs-internal.h | 1 +
refs/reftable-backend.c | 1418 +++++++++++++++++
reftable/.gitattributes | 1 +
reftable/LICENSE | 31 +
reftable/VERSION | 1 +
reftable/basics.c | 144 ++
reftable/basics.h | 56 +
reftable/basics_test.c | 56 +
reftable/block.c | 440 +++++
reftable/block.h | 129 ++
reftable/block_test.c | 119 ++
reftable/blocksource.c | 148 ++
reftable/blocksource.h | 22 +
reftable/compat.h | 48 +
reftable/constants.h | 21 +
reftable/dump.c | 219 +++
reftable/error.c | 39 +
reftable/iter.c | 242 +++
reftable/iter.h | 75 +
reftable/merged.c | 366 +++++
reftable/merged.h | 35 +
reftable/merged_test.c | 333 ++++
reftable/pq.c | 115 ++
reftable/pq.h | 32 +
reftable/publicbasics.c | 58 +
reftable/reader.c | 733 +++++++++
reftable/reader.h | 75 +
reftable/record.c | 1116 +++++++++++++
reftable/record.h | 139 ++
reftable/record_test.c | 404 +++++
reftable/refname.c | 209 +++
reftable/refname.h | 29 +
reftable/refname_test.c | 100 ++
reftable/reftable-blocksource.h | 50 +
reftable/reftable-error.h | 62 +
reftable/reftable-generic.h | 49 +
reftable/reftable-iterator.h | 37 +
reftable/reftable-malloc.h | 20 +
reftable/reftable-merged.h | 68 +
reftable/reftable-reader.h | 89 ++
reftable/reftable-record.h | 73 +
reftable/reftable-stack.h | 116 ++
reftable/reftable-tests.h | 22 +
reftable/reftable-writer.h | 149 ++
reftable/reftable.c | 98 ++
reftable/reftable_test.c | 577 +++++++
reftable/stack.c | 1247 +++++++++++++++
reftable/stack.h | 41 +
reftable/stack_test.c | 781 +++++++++
reftable/system.h | 32 +
reftable/test_framework.c | 23 +
reftable/test_framework.h | 48 +
reftable/tree.c | 63 +
reftable/tree.h | 34 +
reftable/tree_test.c | 61 +
reftable/writer.c | 676 ++++++++
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 | 14 +
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, 11951 insertions(+), 39 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/compat.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: faefdd61ec7c7f6f3c8c9907891465ac9a2a1475
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-847%2Fhanwen%2Flibreftable-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-847/hanwen/libreftable-v3
Pull-Request: https://github.com/git/git/pull/847
Range-diff vs v2:
-: ---------- > 1: 030998a732 move sleep_millisec to git-compat-util.h
-: ---------- > 2: cf667653df init-db: set the_repository->hash_algo early on
1: 6228103b4a = 3: 91c3ac2449 reftable: add LICENSE
2: 5d1b946ab5 ! 4: 2aa30f536f reftable: define the public API
@@ Metadata
Author: Han-Wen Nienhuys <hanwen@google.com>
## Commit message ##
- reftable: define the public API
+ reftable: add error related functionality
+
+ The reftable/ directory is structured as a library, so it cannot
+ crash on misuse. Instead, it returns an error codes.
+
+ In addition, the error code can be used to signal conditions from lower levels
+ of the library to be handled by higher levels of the library. For example, a
+ transaction might legitimately write an empty reftable file, but in that case,
+ we'd want to shortcut the transaction overhead.
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
- ## reftable/reftable.h (new) ##
+ ## reftable/error.c (new) ##
@@
+/*
+Copyright 2020 Google LLC
@@ reftable/reftable.h (new)
+https://developers.google.com/open-source/licenses/bsd
+*/
+
-+#ifndef REFTABLE_H
-+#define REFTABLE_H
-+
-+#include <stdint.h>
-+#include <stddef.h>
-+
-+void reftable_set_alloc(void *(*malloc)(size_t),
-+ void *(*realloc)(void *, size_t), void (*free)(void *));
-+
-+/****************************************************************
-+ 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. */
-+};
-+
-+/* 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 */
-+void reftable_ref_record_print(struct reftable_ref_record *ref,
-+ uint32_t hash_id);
-+
-+/* frees and nulls all pointer values. */
-+void reftable_ref_record_clear(struct reftable_ref_record *ref);
-+
-+/* returns whether two reftable_ref_records are the same */
-+int reftable_ref_record_equal(struct reftable_ref_record *a,
-+ struct reftable_ref_record *b, int hash_size);
-+
-+/* reftable_log_record holds a reflog entry */
-+struct reftable_log_record {
-+ char *refname;
-+ uint64_t update_index; /* logical timestamp of a transactional update.
-+ */
-+ uint8_t *new_hash;
-+ uint8_t *old_hash;
-+ char *name;
-+ char *email;
-+ uint64_t time;
-+ int16_t tz_offset;
-+ char *message;
-+};
-+
-+/* returns whether 'ref' represents the deletion of a log record. */
-+int reftable_log_record_is_deletion(const struct reftable_log_record *log);
-+
-+/* frees and nulls all pointer values. */
-+void reftable_log_record_clear(struct reftable_log_record *log);
-+
-+/* returns whether two records are equal. */
-+int reftable_log_record_equal(struct reftable_log_record *a,
-+ struct reftable_log_record *b, int hash_size);
-+
-+/* dumps a reftable_log_record on stdout, for debugging/testing. */
-+void reftable_log_record_print(struct reftable_log_record *log,
-+ uint32_t hash_id);
++#include "reftable-error.h"
++
++#include <stdio.h>
++
++const char *reftable_error_str(int err)
++{
++ static char buf[250];
++ switch (err) {
++ case REFTABLE_IO_ERROR:
++ return "I/O error";
++ case REFTABLE_FORMAT_ERROR:
++ return "corrupt reftable file";
++ case REFTABLE_NOT_EXIST_ERROR:
++ return "file does not exist";
++ case REFTABLE_LOCK_ERROR:
++ return "data is outdated";
++ case REFTABLE_API_ERROR:
++ return "misuse of the reftable API";
++ case REFTABLE_ZLIB_ERROR:
++ return "zlib failure";
++ case REFTABLE_NAME_CONFLICT:
++ return "file/directory conflict";
++ case REFTABLE_REFNAME_ERROR:
++ return "invalid refname";
++ case -1:
++ return "general error";
++ default:
++ snprintf(buf, sizeof(buf), "unknown error code %d", err);
++ return buf;
++ }
++}
+
+ ## reftable/reftable-error.h (new) ##
+@@
++/*
++Copyright 2020 Google LLC
+
-+/****************************************************************
-+ Error handling
++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
++*/
+
-+ Error are signaled with negative integer return values. 0 means success.
-+ ****************************************************************/
++#ifndef REFTABLE_ERROR_H
++#define REFTABLE_ERROR_H
+
-+/* different types of errors */
++/*
++ 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,
@@ reftable/reftable.h (new)
+ - 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,
+
@@ reftable/reftable.h (new)
+ * deallocated. */
+const char *reftable_error_str(int err);
+
-+/*
-+ * Convert the numeric error code to an equivalent errno code.
-+ */
-+int reftable_error_to_errno(int err);
-+
-+/****************************************************************
-+ Writing
-+
-+ Writing single reftables
-+ ****************************************************************/
-+
-+/* reftable_write_options sets options for writing a single reftable. */
-+struct reftable_write_options {
-+ /* boolean: do not pad out blocks to block size. */
-+ int unpadded;
-+
-+ /* the blocksize. Should be less than 2^24. */
-+ uint32_t block_size;
-+
-+ /* boolean: do not generate a SHA1 => ref index. */
-+ int skip_index_objects;
-+
-+ /* how often to write complete keys in each block. */
-+ int restart_interval;
-+
-+ /* 4-byte identifier ("sha1", "s256") of the hash.
-+ * Defaults to SHA1 if unset
-+ */
-+ uint32_t hash_id;
-+
-+ /* boolean: do not check ref names for validity or dir/file conflicts.
-+ */
-+ int skip_name_check;
-+
-+ /* boolean: copy log messages exactly. If unset, check that the message
-+ * is a single line, and add '\n' if missing.
-+ */
-+ int exact_log_message;
-+};
-+
-+/* reftable_block_stats holds statistics for a single block type */
-+struct reftable_block_stats {
-+ /* total number of entries written */
-+ int entries;
-+ /* total number of key restarts */
-+ int restarts;
-+ /* total number of blocks */
-+ int blocks;
-+ /* total number of index blocks */
-+ int index_blocks;
-+ /* depth of the index */
-+ int max_index_level;
-+
-+ /* offset of the first block for this type */
-+ uint64_t offset;
-+ /* offset of the top level index block for this type, or 0 if not
-+ * present */
-+ uint64_t index_offset;
-+};
-+
-+/* stats holds overall statistics for a single reftable */
-+struct reftable_stats {
-+ /* total number of blocks written. */
-+ int blocks;
-+ /* stats for ref data */
-+ struct reftable_block_stats ref_stats;
-+ /* stats for the SHA1 to ref map. */
-+ struct reftable_block_stats obj_stats;
-+ /* stats for index blocks */
-+ struct reftable_block_stats idx_stats;
-+ /* stats for log blocks */
-+ struct reftable_block_stats log_stats;
-+
-+ /* disambiguation length of shortened object IDs. */
-+ int object_id_len;
-+};
-+
-+/* reftable_new_writer creates a new writer */
-+struct reftable_writer *
-+reftable_new_writer(int (*writer_func)(void *, const void *, size_t),
-+ void *writer_arg, struct reftable_write_options *opts);
-+
-+/* write to a file descriptor. fdp should be an int* pointing to the fd. */
-+int reftable_fd_write(void *fdp, const void *data, size_t size);
-+
-+/* Set the range of update indices for the records we will add. When
-+ writing a table into a stack, the min should be at least
-+ reftable_stack_next_update_index(), or REFTABLE_API_ERROR is returned.
-+
-+ For transactional updates, typically min==max. When converting an existing
-+ ref database into a single reftable, this would be a range of update-index
-+ timestamps.
-+ */
-+void reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
-+ uint64_t max);
-+
-+/* adds a reftable_ref_record. Must be called in ascending
-+ order. The update_index must be within the limits set by
-+ reftable_writer_set_limits(), or REFTABLE_API_ERROR is returned.
-+
-+ It is an error to write a ref record after a log record.
-+ */
-+int reftable_writer_add_ref(struct reftable_writer *w,
-+ struct reftable_ref_record *ref);
-+
-+/* Convenience function to add multiple refs. Will sort the refs by
-+ name before adding. */
-+int reftable_writer_add_refs(struct reftable_writer *w,
-+ struct reftable_ref_record *refs, int n);
-+
-+/* adds a reftable_log_record. Must be called in ascending order (with more
-+ recent log entries first.)
-+ */
-+int reftable_writer_add_log(struct reftable_writer *w,
-+ struct reftable_log_record *log);
-+
-+/* Convenience function to add multiple logs. Will sort the records by
-+ key before adding. */
-+int reftable_writer_add_logs(struct reftable_writer *w,
-+ struct reftable_log_record *logs, int n);
-+
-+/* reftable_writer_close finalizes the reftable. The writer is retained so
-+ * statistics can be inspected. */
-+int reftable_writer_close(struct reftable_writer *w);
-+
-+/* writer_stats returns the statistics on the reftable being written.
-+
-+ This struct becomes invalid when the writer is freed.
-+ */
-+const struct reftable_stats *writer_stats(struct reftable_writer *w);
-+
-+/* reftable_writer_free deallocates memory for the writer */
-+void reftable_writer_free(struct reftable_writer *w);
-+
-+/****************************************************************
-+ * ITERATING
-+ ****************************************************************/
-+
-+/* iterator is the generic interface for walking over data stored in a
-+ reftable. It is generally passed around by value.
-+*/
-+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.
-+*/
-+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.
-+*/
-+int reftable_iterator_next_log(struct reftable_iterator *it,
-+ struct reftable_log_record *log);
-+
-+/* releases resources associated with an iterator. */
-+void reftable_iterator_destroy(struct reftable_iterator *it);
-+
-+/****************************************************************
-+ 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.
-+ ****************************************************************/
-+
-+/* block_source is a generic wrapper for a seekable readable file.
-+ It is generally passed around by value.
-+ */
-+struct reftable_block_source {
-+ struct reftable_block_source_vtable *ops;
-+ void *arg;
-+};
-+
-+/* a contiguous segment of bytes. It keeps track of its generating block_source
-+ so it can return itself into the pool.
-+*/
-+struct reftable_block {
-+ uint8_t *data;
-+ int len;
-+ struct reftable_block_source source;
-+};
-+
-+/* block_source_vtable are the operations that make up block_source */
-+struct reftable_block_source_vtable {
-+ /* returns the size of a block source */
-+ uint64_t (*size)(void *source);
-+
-+ /* reads a segment from the block source. It is an error to read
-+ beyond the end of the block */
-+ int (*read_block)(void *source, struct reftable_block *dest,
-+ uint64_t off, uint32_t size);
-+ /* mark the block as read; may return the data back to malloc */
-+ void (*return_block)(void *source, struct reftable_block *blockp);
-+
-+ /* release all resources associated with the block source */
-+ void (*close)(void *source);
-+};
-+
-+/* opens a file on the file system as a block_source */
-+int reftable_block_source_from_file(struct reftable_block_source *block_src,
-+ const char *name);
-+
-+/* The reader struct is a handle to an open reftable file. */
-+struct reftable_reader;
-+
-+/* reftable_new_reader opens a reftable for reading. If successful, returns 0
-+ * code and sets pp. The name is used for creating a stack. Typically, it is the
-+ * basename of the file. The block source `src` is owned by the reader, and is
-+ * closed on calling reftable_reader_destroy().
-+ */
-+int reftable_new_reader(struct reftable_reader **pp,
-+ struct reftable_block_source *src, const char *name);
-+
-+/* reftable_reader_seek_ref returns an iterator where 'name' would be inserted
-+ in the table. To seek to the start of the table, use name = "".
-+
-+ example:
-+
-+ struct reftable_reader *r = NULL;
-+ int err = reftable_new_reader(&r, &src, "filename");
-+ if (err < 0) { ... }
-+ struct reftable_iterator it = {0};
-+ err = reftable_reader_seek_ref(r, &it, "refs/heads/master");
-+ if (err < 0) { ... }
-+ struct reftable_ref_record ref = {0};
-+ while (1) {
-+ err = reftable_iterator_next_ref(&it, &ref);
-+ if (err > 0) {
-+ break;
-+ }
-+ if (err < 0) {
-+ ..error handling..
-+ }
-+ ..found..
-+ }
-+ reftable_iterator_destroy(&it);
-+ reftable_ref_record_clear(&ref);
-+ */
-+int reftable_reader_seek_ref(struct reftable_reader *r,
-+ struct reftable_iterator *it, const char *name);
-+
-+/* returns the hash ID used in this table. */
-+uint32_t reftable_reader_hash_id(struct reftable_reader *r);
-+
-+/* seek to logs for the given name, older than update_index. To seek to the
-+ start of the table, use name = "".
-+ */
-+int reftable_reader_seek_log_at(struct reftable_reader *r,
-+ struct reftable_iterator *it, const char *name,
-+ uint64_t update_index);
-+
-+/* seek to newest log entry for given name. */
-+int reftable_reader_seek_log(struct reftable_reader *r,
-+ struct reftable_iterator *it, const char *name);
-+
-+/* closes and deallocates a reader. */
-+void reftable_reader_free(struct reftable_reader *);
-+
-+/* return an iterator for the refs pointing to `oid`. */
-+int reftable_reader_refs_for(struct reftable_reader *r,
-+ struct reftable_iterator *it, uint8_t *oid);
-+
-+/* return the max_update_index for a table */
-+uint64_t reftable_reader_max_update_index(struct reftable_reader *r);
-+
-+/* return the min_update_index for a table */
-+uint64_t reftable_reader_min_update_index(struct reftable_reader *r);
-+
-+/****************************************************************
-+ 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.
-+ ****************************************************************/
-+
-+/* A merged table is implements seeking/iterating over a stack of tables. */
-+struct reftable_merged_table;
-+
-+/* A generic reftable; see below. */
-+struct reftable_table;
-+
-+/* reftable_new_merged_table creates a new merged table. It takes ownership of
-+ the stack array.
-+*/
-+int reftable_new_merged_table(struct reftable_merged_table **dest,
-+ struct reftable_table *stack, int n,
-+ uint32_t hash_id);
-+
-+/* returns an iterator positioned just before 'name' */
-+int reftable_merged_table_seek_ref(struct reftable_merged_table *mt,
-+ struct reftable_iterator *it,
-+ const char *name);
-+
-+/* returns an iterator for log entry, at given update_index */
-+int reftable_merged_table_seek_log_at(struct reftable_merged_table *mt,
-+ struct reftable_iterator *it,
-+ const char *name, uint64_t update_index);
-+
-+/* like reftable_merged_table_seek_log_at but look for the newest entry. */
-+int reftable_merged_table_seek_log(struct reftable_merged_table *mt,
-+ struct reftable_iterator *it,
-+ const char *name);
-+
-+/* returns the max update_index covered by this merged table. */
-+uint64_t
-+reftable_merged_table_max_update_index(struct reftable_merged_table *mt);
-+
-+/* returns the min update_index covered by this merged table. */
-+uint64_t
-+reftable_merged_table_min_update_index(struct reftable_merged_table *mt);
-+
-+/* releases memory for the merged_table */
-+void reftable_merged_table_free(struct reftable_merged_table *m);
-+
-+/* return the hash ID of the merged table. */
-+uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *m);
-+
-+/****************************************************************
-+ Generic tables
-+
-+ A unified API for reading tables, either merged tables, or single readers.
-+ ****************************************************************/
-+
-+struct reftable_table {
-+ struct reftable_table_vtable *ops;
-+ void *table_arg;
-+};
-+
-+int reftable_table_seek_ref(struct reftable_table *tab,
-+ struct reftable_iterator *it, const char *name);
-+
-+void reftable_table_from_reader(struct reftable_table *tab,
-+ struct reftable_reader *reader);
-+
-+/* returns the hash ID from a generic reftable_table */
-+uint32_t reftable_table_hash_id(struct reftable_table *tab);
-+
-+/* create a generic table from reftable_merged_table */
-+void reftable_table_from_merged_table(struct reftable_table *tab,
-+ struct reftable_merged_table *table);
-+
-+/* returns the max update_index covered by this table. */
-+uint64_t reftable_table_max_update_index(struct reftable_table *tab);
-+
-+/* returns the min update_index covered by this table. */
-+uint64_t reftable_table_min_update_index(struct reftable_table *tab);
-+
-+/* convenience function to read a single ref. Returns < 0 for error, 0
-+ for success, and 1 if ref not found. */
-+int reftable_table_read_ref(struct reftable_table *tab, const char *name,
-+ struct reftable_ref_record *ref);
-+
-+/****************************************************************
-+ Mutable ref database
-+
-+ The stack presents an interface to a mutable sequence of reftables.
-+ ****************************************************************/
-+
-+/* a stack is a stack of reftables, which can be mutated by pushing a table to
-+ * the top of the stack */
-+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.
-+*/
-+int reftable_new_stack(struct reftable_stack **dest, const char *dir,
-+ struct reftable_write_options config);
-+
-+/* returns the update_index at which a next table should be written. */
-+uint64_t reftable_stack_next_update_index(struct reftable_stack *st);
-+
-+/* holds a transaction to add tables at the top of a stack. */
-+struct reftable_addition;
-+
-+/*
-+ 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);
-+
-+/* Adds a reftable to transaction. */
-+int reftable_addition_add(struct reftable_addition *add,
-+ int (*write_table)(struct reftable_writer *wr,
-+ void *arg),
-+ void *arg);
-+
-+/* Commits the transaction, releasing the lock. */
-+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. */
-+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. */
-+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.
-+*/
-+struct reftable_merged_table *
-+reftable_stack_merged_table(struct reftable_stack *st);
-+
-+/* frees all resources associated with the stack. */
-+void reftable_stack_destroy(struct reftable_stack *st);
-+
-+/* Reloads the stack if necessary. This is very cheap to run if the stack was up
-+ * to date */
-+int reftable_stack_reload(struct reftable_stack *st);
-+
-+/* Policy for expiring reflog entries. */
-+struct reftable_log_expiry_config {
-+ /* Drop entries older than this timestamp */
-+ uint64_t time;
-+
-+ /* Drop older entries */
-+ uint64_t min_update_index;
-+};
-+
-+/* compacts all reftables into a giant table. Expire reflog entries if config is
-+ * non-NULL */
-+int reftable_stack_compact_all(struct reftable_stack *st,
-+ struct reftable_log_expiry_config *config);
-+
-+/* 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. */
-+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. */
-+int reftable_stack_read_log(struct reftable_stack *st, const char *refname,
-+ struct reftable_log_record *log);
-+
-+/* statistics on past compactions. */
-+struct reftable_compaction_stats {
-+ uint64_t bytes; /* total number of bytes written */
-+ uint64_t entries_written; /* total number of entries written, including
-+ failures. */
-+ int attempts; /* how often we tried to compact */
-+ int failures; /* failures happen on concurrent updates */
-+};
-+
-+/* return statistics for compaction up till now. */
-+struct reftable_compaction_stats *
-+reftable_stack_compaction_stats(struct reftable_stack *st);
-+
+#endif
3: 01a669a731 < -: ---------- vcxproj: adjust for the reftable changes
5: 4190da597e ! 5: 987d1d186f reftable: utility functions
@@ Commit message
This commit provides basic utility classes for the reftable library.
- Since the reftable library must compile standalone, there may be some overlap
- with git-core utility functions.
-
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
## Makefile ##
@@ Makefile: TEST_SHELL_PATH = $(SHELL_PATH)
+REFTABLE_LIB = reftable/libreftable.a
+REFTABLE_TEST_LIB = reftable/libreftable_test.a
- GENERATED_H += config-list.h
GENERATED_H += command-list.h
+ GENERATED_H += config-list.h
@@ Makefile: THIRD_PARTY_SOURCES += compat/regex/%
THIRD_PARTY_SOURCES += sha1collisiondetection/%
THIRD_PARTY_SOURCES += sha1dc/%
@@ Makefile: XDIFF_OBJS += xdiff/xpatience.o
XDIFF_OBJS += xdiff/xutils.o
+REFTABLE_OBJS += reftable/basics.o
-+REFTABLE_OBJS += reftable/blocksource.o
++REFTABLE_OBJS += reftable/error.o
+REFTABLE_OBJS += reftable/publicbasics.o
-+REFTABLE_OBJS += reftable/compat.o
-+REFTABLE_OBJS += reftable/strbuf.o
+
-+REFTABLE_TEST_OBJS += reftable/strbuf_test.o
+REFTABLE_TEST_OBJS += reftable/test_framework.o
++REFTABLE_TEST_OBJS += reftable/basics_test.o
+
TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
@@ reftable/basics.c (new)
+ }
+
+ return *a == *b;
++}
++
++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]) {
++ break;
++ }
++ p++;
++ }
++
++ return p;
+}
## reftable/basics.h (new) ##
@@ reftable/basics.h (new)
+#ifndef BASICS_H
+#define BASICS_H
+
++/*
++ * miscellaneous utilities that are not provided by Git.
++ */
++
+#include "system.h"
+
+/* Bigendian en/decoding of integers */
@@ reftable/basics.h (new)
+void reftable_free(void *p);
+void *reftable_calloc(size_t sz);
+
++/* Find the longest shared prefix size of `a` and `b` */
++struct strbuf;
++int common_prefix_size(struct strbuf *a, struct strbuf *b);
++
+#endif
- ## reftable/blocksource.c (new) ##
+ ## reftable/basics_test.c (new) ##
@@
+/*
+Copyright 2020 Google LLC
@@ reftable/blocksource.c (new)
+#include "system.h"
+
+#include "basics.h"
-+#include "blocksource.h"
-+#include "strbuf.h"
-+#include "reftable.h"
-+
-+static void strbuf_return_block(void *b, struct reftable_block *dest)
-+{
-+ memset(dest->data, 0xff, dest->len);
-+ reftable_free(dest->data);
-+}
-+
-+static void strbuf_close(void *b)
-+{
-+}
-+
-+static int strbuf_read_block(void *v, struct reftable_block *dest, uint64_t off,
-+ uint32_t size)
-+{
-+ struct strbuf *b = (struct strbuf *)v;
-+ assert(off + size <= b->len);
-+ dest->data = reftable_calloc(size);
-+ memcpy(dest->data, b->buf + off, size);
-+ dest->len = size;
-+ return size;
-+}
-+
-+static uint64_t strbuf_size(void *b)
-+{
-+ return ((struct strbuf *)b)->len;
-+}
-+
-+static struct reftable_block_source_vtable strbuf_vtable = {
-+ .size = &strbuf_size,
-+ .read_block = &strbuf_read_block,
-+ .return_block = &strbuf_return_block,
-+ .close = &strbuf_close,
-+};
-+
-+void block_source_from_strbuf(struct reftable_block_source *bs,
-+ struct strbuf *buf)
-+{
-+ assert(bs->ops == NULL);
-+ bs->ops = &strbuf_vtable;
-+ bs->arg = buf;
-+}
-+
-+static void malloc_return_block(void *b, struct reftable_block *dest)
-+{
-+ memset(dest->data, 0xff, dest->len);
-+ reftable_free(dest->data);
-+}
-+
-+static struct reftable_block_source_vtable malloc_vtable = {
-+ .return_block = &malloc_return_block,
-+};
-+
-+static struct reftable_block_source malloc_block_source_instance = {
-+ .ops = &malloc_vtable,
-+};
-+
-+struct reftable_block_source malloc_block_source(void)
-+{
-+ return malloc_block_source_instance;
-+}
++#include "test_framework.h"
++#include "reftable-tests.h"
+
-+struct file_block_source {
-+ int fd;
-+ uint64_t size;
++struct binsearch_args {
++ int key;
++ int *arr;
+};
+
-+static uint64_t file_size(void *b)
++static int binsearch_func(size_t i, void *void_args)
+{
-+ return ((struct file_block_source *)b)->size;
-+}
++ struct binsearch_args *args = (struct binsearch_args *)void_args;
+
-+static void file_return_block(void *b, struct reftable_block *dest)
-+{
-+ memset(dest->data, 0xff, dest->len);
-+ reftable_free(dest->data);
++ return args->key < args->arr[i];
+}
+
-+static void file_close(void *b)
-+{
-+ int fd = ((struct file_block_source *)b)->fd;
-+ if (fd > 0) {
-+ close(fd);
-+ ((struct file_block_source *)b)->fd = 0;
-+ }
-+
-+ reftable_free(b);
-+}
-+
-+static int file_read_block(void *v, struct reftable_block *dest, uint64_t off,
-+ uint32_t size)
-+{
-+ struct file_block_source *b = (struct file_block_source *)v;
-+ assert(off + size <= b->size);
-+ dest->data = reftable_malloc(size);
-+ if (pread(b->fd, dest->data, size, off) != size)
-+ return -1;
-+ dest->len = size;
-+ return size;
-+}
-+
-+static struct reftable_block_source_vtable file_vtable = {
-+ .size = &file_size,
-+ .read_block = &file_read_block,
-+ .return_block = &file_return_block,
-+ .close = &file_close,
-+};
-+
-+int reftable_block_source_from_file(struct reftable_block_source *bs,
-+ const char *name)
++static void test_binsearch(void)
+{
-+ struct stat st = { 0 };
-+ int err = 0;
-+ int fd = open(name, O_RDONLY);
-+ struct file_block_source *p = NULL;
-+ if (fd < 0) {
-+ if (errno == ENOENT) {
-+ return REFTABLE_NOT_EXIST_ERROR;
-+ }
-+ return -1;
-+ }
-+
-+ err = fstat(fd, &st);
-+ if (err < 0)
-+ return -1;
-+
-+ p = reftable_calloc(sizeof(struct file_block_source));
-+ p->size = st.st_size;
-+ p->fd = fd;
-+
-+ assert(bs->ops == NULL);
-+ bs->ops = &file_vtable;
-+ bs->arg = p;
-+ return 0;
-+}
-
- ## reftable/blocksource.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 BLOCKSOURCE_H
-+#define BLOCKSOURCE_H
-+
-+#include "strbuf.h"
-+
-+struct reftable_block_source;
-+
-+/* Create an in-memory block source for reading reftables */
-+void block_source_from_strbuf(struct reftable_block_source *bs,
-+ struct strbuf *buf);
++ int arr[] = { 2, 4, 6, 8, 10 };
++ size_t sz = ARRAY_SIZE(arr);
++ struct binsearch_args args = {
++ .arr = arr,
++ };
+
-+struct reftable_block_source malloc_block_source(void);
-+
-+#endif
-
- ## reftable/compat.c (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
-+
-+*/
-+
-+/* compat.c - compatibility functions for standalone compilation */
-+
-+#include "system.h"
-+#include "basics.h"
-+
-+#ifdef REFTABLE_STANDALONE
-+
-+#include <dirent.h>
-+
-+void put_be32(void *p, uint32_t i)
-+{
-+ uint8_t *out = (uint8_t *)p;
-+
-+ out[0] = (uint8_t)((i >> 24) & 0xff);
-+ out[1] = (uint8_t)((i >> 16) & 0xff);
-+ out[2] = (uint8_t)((i >> 8) & 0xff);
-+ out[3] = (uint8_t)((i)&0xff);
-+}
-+
-+uint32_t get_be32(uint8_t *in)
-+{
-+ return (uint32_t)(in[0]) << 24 | (uint32_t)(in[1]) << 16 |
-+ (uint32_t)(in[2]) << 8 | (uint32_t)(in[3]);
-+}
-+
-+void put_be64(void *p, uint64_t v)
-+{
-+ uint8_t *out = (uint8_t *)p;
-+ int i = sizeof(uint64_t);
-+ while (i--) {
-+ out[i] = (uint8_t)(v & 0xff);
-+ v >>= 8;
-+ }
-+}
-+
-+uint64_t get_be64(void *out)
-+{
-+ uint8_t *bytes = (uint8_t *)out;
-+ uint64_t v = 0;
+ int i = 0;
-+ for (i = 0; i < sizeof(uint64_t); i++) {
-+ v = (v << 8) | (uint8_t)(bytes[i] & 0xff);
-+ }
-+ return v;
-+}
-+
-+uint16_t get_be16(uint8_t *in)
-+{
-+ return (uint32_t)(in[0]) << 8 | (uint32_t)(in[1]);
-+}
-+
-+char *xstrdup(const char *s)
-+{
-+ int l = strlen(s);
-+ char *dest = (char *)reftable_malloc(l + 1);
-+ strncpy(dest, s, l + 1);
-+ return dest;
-+}
-+
-+void sleep_millisec(int millisecs)
-+{
-+ usleep(millisecs * 1000);
-+}
-+
-+void reftable_clear_dir(const char *dirname)
-+{
-+ DIR *dir = opendir(dirname);
-+ struct dirent *ent = NULL;
-+ assert(dir);
-+ while ((ent = readdir(dir)) != NULL) {
-+ unlinkat(dirfd(dir), ent->d_name, 0);
++ for (i = 1; i < 11; i++) {
++ int res;
++ args.key = i;
++ res = binsearch(sz, &binsearch_func, &args);
++
++ if (res < sz) {
++ EXPECT(args.key < arr[res]);
++ if (res > 0) {
++ EXPECT(args.key >= arr[res - 1]);
++ }
++ } else {
++ EXPECT(args.key == 10 || args.key == 11);
++ }
+ }
-+ closedir(dir);
-+ rmdir(dirname);
+}
+
-+#else
-+
-+#include "../dir.h"
-+
-+void reftable_clear_dir(const char *dirname)
++int basics_test_main(int argc, const char *argv[])
+{
-+ struct strbuf path = STRBUF_INIT;
-+ strbuf_addstr(&path, dirname);
-+ remove_dir_recursively(&path, 0);
-+ strbuf_release(&path);
-+}
-+
-+#endif
-+
-+int hash_size(uint32_t id)
-+{
-+ switch (id) {
-+ case 0:
-+ case SHA1_ID:
-+ return SHA1_SIZE;
-+ case SHA256_ID:
-+ return SHA256_SIZE;
-+ }
-+ abort();
++ test_binsearch();
++ return 0;
+}
## reftable/compat.h (new) ##
@@ reftable/publicbasics.c (new)
+https://developers.google.com/open-source/licenses/bsd
+*/
+
-+#include "reftable.h"
++#include "reftable-malloc.h"
+
+#include "basics.h"
+#include "system.h"
+
-+const char *reftable_error_str(int err)
-+{
-+ static char buf[250];
-+ switch (err) {
-+ case REFTABLE_IO_ERROR:
-+ return "I/O error";
-+ case REFTABLE_FORMAT_ERROR:
-+ return "corrupt reftable file";
-+ case REFTABLE_NOT_EXIST_ERROR:
-+ return "file does not exist";
-+ case REFTABLE_LOCK_ERROR:
-+ return "data is outdated";
-+ case REFTABLE_API_ERROR:
-+ return "misuse of the reftable API";
-+ case REFTABLE_ZLIB_ERROR:
-+ return "zlib failure";
-+ case REFTABLE_NAME_CONFLICT:
-+ return "file/directory conflict";
-+ case REFTABLE_REFNAME_ERROR:
-+ return "invalid refname";
-+ case -1:
-+ return "general error";
-+ default:
-+ snprintf(buf, sizeof(buf), "unknown error code %d", err);
-+ return buf;
-+ }
-+}
-+
-+int reftable_error_to_errno(int err)
-+{
-+ switch (err) {
-+ case REFTABLE_IO_ERROR:
-+ return EIO;
-+ case REFTABLE_FORMAT_ERROR:
-+ return EFAULT;
-+ case REFTABLE_NOT_EXIST_ERROR:
-+ return ENOENT;
-+ case REFTABLE_LOCK_ERROR:
-+ return EBUSY;
-+ case REFTABLE_API_ERROR:
-+ return EINVAL;
-+ case REFTABLE_ZLIB_ERROR:
-+ return EDOM;
-+ default:
-+ return ERANGE;
-+ }
-+}
-+
+static void *(*reftable_malloc_ptr)(size_t sz) = &malloc;
+static void *(*reftable_realloc_ptr)(void *, size_t) = &realloc;
+static void (*reftable_free_ptr)(void *) = &free;
@@ reftable/publicbasics.c (new)
+ reftable_free_ptr = free;
+}
+
-+int reftable_fd_write(void *arg, const void *data, size_t sz)
++int hash_size(uint32_t id)
+{
-+ int *fdp = (int *)arg;
-+ return write(*fdp, data, sz);
++ switch (id) {
++ case 0:
++ case SHA1_ID:
++ return SHA1_SIZE;
++ case SHA256_ID:
++ return SHA256_SIZE;
++ }
++ abort();
+}
- ## reftable/reftable-tests.h (new) ##
+ ## reftable/reftable-malloc.h (new) ##
@@
+/*
+Copyright 2020 Google LLC
@@ reftable/reftable-tests.h (new)
+https://developers.google.com/open-source/licenses/bsd
+*/
+
-+#ifndef REFTABLE_TESTS_H
-+#define REFTABLE_TESTS_H
++#ifndef REFTABLE_H
++#define REFTABLE_H
+
-+int block_test_main(int argc, const char **argv);
-+int merged_test_main(int argc, const char **argv);
-+int record_test_main(int argc, const char **argv);
-+int refname_test_main(int argc, const char **argv);
-+int reftable_test_main(int argc, const char **argv);
-+int strbuf_test_main(int argc, const char **argv);
-+int stack_test_main(int argc, const char **argv);
-+int tree_test_main(int argc, const char **argv);
-+int reftable_dump_main(int argc, char *const *argv);
++#include <stddef.h>
++
++/*
++ Overrides the functions to use for memory management.
++ */
++void reftable_set_alloc(void *(*malloc)(size_t),
++ void *(*realloc)(void *, size_t), void (*free)(void *));
+
+#endif
- ## reftable/strbuf.c (new) ##
+ ## reftable/reftable-tests.h (new) ##
@@
+/*
+Copyright 2020 Google LLC
@@ reftable/strbuf.c (new)
+https://developers.google.com/open-source/licenses/bsd
+*/
+
-+#include "strbuf.h"
-+
-+#ifdef REFTABLE_STANDALONE
-+
-+void strbuf_init(struct strbuf *s, size_t alloc)
-+{
-+ struct strbuf empty = STRBUF_INIT;
-+ *s = empty;
-+}
-+
-+void strbuf_grow(struct strbuf *s, size_t extra)
-+{
-+ size_t newcap = s->len + extra + 1;
-+ if (newcap > s->cap) {
-+ s->buf = reftable_realloc(s->buf, newcap);
-+ s->cap = newcap;
-+ }
-+}
-+
-+static void strbuf_resize(struct strbuf *s, int l)
-+{
-+ int zl = l + 1; /* one uint8_t for 0 termination. */
-+ assert(s->canary == STRBUF_CANARY);
-+ if (s->cap < zl) {
-+ int c = s->cap * 2;
-+ if (c < zl) {
-+ c = zl;
-+ }
-+ s->cap = c;
-+ s->buf = reftable_realloc(s->buf, s->cap);
-+ }
-+ s->len = l;
-+ s->buf[l] = 0;
-+}
-+
-+void strbuf_setlen(struct strbuf *s, size_t l)
-+{
-+ assert(s->cap >= l + 1);
-+ s->len = l;
-+ s->buf[l] = 0;
-+}
-+
-+void strbuf_reset(struct strbuf *s)
-+{
-+ strbuf_resize(s, 0);
-+}
-+
-+void strbuf_addstr(struct strbuf *d, const char *s)
-+{
-+ int l1 = d->len;
-+ int l2 = strlen(s);
-+ assert(d->canary == STRBUF_CANARY);
-+
-+ strbuf_resize(d, l2 + l1);
-+ memcpy(d->buf + l1, s, l2);
-+}
-+
-+void strbuf_addbuf(struct strbuf *s, struct strbuf *a)
-+{
-+ int end = s->len;
-+ assert(s->canary == STRBUF_CANARY);
-+ strbuf_resize(s, s->len + a->len);
-+ memcpy(s->buf + end, a->buf, a->len);
-+}
-+
-+char *strbuf_detach(struct strbuf *s, size_t *sz)
-+{
-+ char *p = NULL;
-+ p = (char *)s->buf;
-+ if (sz)
-+ *sz = s->len;
-+ s->buf = NULL;
-+ s->cap = 0;
-+ s->len = 0;
-+ return p;
-+}
-+
-+void strbuf_release(struct strbuf *s)
-+{
-+ assert(s->canary == STRBUF_CANARY);
-+ s->cap = 0;
-+ s->len = 0;
-+ reftable_free(s->buf);
-+ s->buf = NULL;
-+}
-+
-+int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
-+{
-+ int min = a->len < b->len ? a->len : b->len;
-+ int res = memcmp(a->buf, b->buf, min);
-+ assert(a->canary == STRBUF_CANARY);
-+ assert(b->canary == STRBUF_CANARY);
-+ if (res != 0)
-+ return res;
-+ if (a->len < b->len)
-+ return -1;
-+ else if (a->len > b->len)
-+ return 1;
-+ else
-+ return 0;
-+}
++#ifndef REFTABLE_TESTS_H
++#define REFTABLE_TESTS_H
+
-+int strbuf_add(struct strbuf *b, const void *data, size_t sz)
-+{
-+ assert(b->canary == STRBUF_CANARY);
-+ strbuf_grow(b, sz);
-+ memcpy(b->buf + b->len, data, sz);
-+ b->len += sz;
-+ b->buf[b->len] = 0;
-+ return sz;
-+}
++int basics_test_main(int argc, const char **argv);
++int block_test_main(int argc, const char **argv);
++int merged_test_main(int argc, const char **argv);
++int record_test_main(int argc, const char **argv);
++int refname_test_main(int argc, const char **argv);
++int reftable_test_main(int argc, const char **argv);
++int stack_test_main(int argc, const char **argv);
++int tree_test_main(int argc, const char **argv);
++int reftable_dump_main(int argc, char *const *argv);
+
+#endif
-+
-+int strbuf_add_void(void *b, const void *data, size_t sz)
-+{
-+ strbuf_add((struct strbuf *)b, data, sz);
-+ return sz;
-+}
-+
-+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]) {
-+ break;
-+ }
-+ p++;
-+ }
-+
-+ return p;
-+}
-+
-+struct strbuf reftable_empty_strbuf = STRBUF_INIT;
- ## reftable/strbuf.h (new) ##
+ ## reftable/system.h (new) ##
@@
+/*
+Copyright 2020 Google LLC
@@ reftable/strbuf.h (new)
+https://developers.google.com/open-source/licenses/bsd
+*/
+
-+#ifndef SLICE_H
-+#define SLICE_H
-+
-+#ifdef REFTABLE_STANDALONE
-+
-+#include "basics.h"
-+
-+/*
-+ Provides a bounds-checked, growable byte ranges. To use, initialize as "strbuf
-+ x = STRBUF_INIT;"
-+ */
-+struct strbuf {
-+ size_t len;
-+ size_t cap;
-+ char *buf;
-+
-+ /* Used to enforce initialization with STRBUF_INIT */
-+ uint8_t canary;
-+};
-+
-+#define STRBUF_CANARY 0x42
-+#define STRBUF_INIT \
-+ { \
-+ 0, 0, NULL, STRBUF_CANARY \
-+ }
-+
-+void strbuf_addstr(struct strbuf *dest, const char *src);
-+
-+/* Deallocate and clear strbuf */
-+void strbuf_release(struct strbuf *strbuf);
-+
-+/* Set strbuf to 0 length, but retain buffer. */
-+void strbuf_reset(struct strbuf *strbuf);
-+
-+/* Initializes a strbuf. Accepts a strbuf with random garbage. */
-+void strbuf_init(struct strbuf *strbuf, size_t alloc);
-+
-+/* Return `buf`, clearing out `s`. Optionally return len (not cap) in `sz`. */
-+char *strbuf_detach(struct strbuf *s, size_t *sz);
-+
-+/* Set length of the slace to `l`, but don't reallocated. */
-+void strbuf_setlen(struct strbuf *s, size_t l);
-+
-+/* Ensure `l` bytes beyond current length are available */
-+void strbuf_grow(struct strbuf *s, size_t l);
-+
-+/* Signed comparison */
-+int strbuf_cmp(const struct strbuf *a, const struct strbuf *b);
-+
-+/* Append `data` to the `dest` strbuf. */
-+int strbuf_add(struct strbuf *dest, const void *data, size_t sz);
++#ifndef SYSTEM_H
++#define SYSTEM_H
+
-+/* Append `add` to `dest. */
-+void strbuf_addbuf(struct strbuf *dest, struct strbuf *add);
++#include "git-compat-util.h"
++#include "strbuf.h"
+
-+#else
++#include <zlib.h>
+
-+#include "../git-compat-util.h"
-+#include "../strbuf.h"
++struct strbuf;
++/* In git, this is declared in dir.h */
++int remove_dir_recursively(struct strbuf *path, int flags);
+
-+#endif
-+
-+extern struct strbuf reftable_empty_strbuf;
++#define SHA1_ID 0x73686131
++#define SHA256_ID 0x73323536
++#define SHA1_SIZE 20
++#define SHA256_SIZE 32
+
-+/* Like strbuf_add, but suitable for passing to reftable_new_writer
++/* This is uncompress2, which is only available in zlib as of 2017.
+ */
-+int strbuf_add_void(void *b, const void *data, size_t sz);
-+
-+/* Find the longest shared prefix size of `a` and `b` */
-+int common_prefix_size(struct strbuf *a, struct strbuf *b);
++int uncompress_return_consumed(Bytef *dest, uLongf *destLen,
++ const Bytef *source, uLong *sourceLen);
++int hash_size(uint32_t id);
+
+#endif
- ## reftable/strbuf_test.c (new) ##
+ ## reftable/test_framework.c (new) ##
@@
+/*
+Copyright 2020 Google LLC
@@ reftable/strbuf_test.c (new)
+https://developers.google.com/open-source/licenses/bsd
+*/
+
-+#include "strbuf.h"
-+
+#include "system.h"
++#include "test_framework.h"
+
+#include "basics.h"
-+#include "test_framework.h"
-+#include "reftable-tests.h"
+
-+static void test_strbuf(void)
++void set_test_hash(uint8_t *p, int i)
+{
-+ struct strbuf s = STRBUF_INIT;
-+ struct strbuf t = STRBUF_INIT;
-+
-+ strbuf_addstr(&s, "abc");
-+ assert(0 == strcmp("abc", s.buf));
-+
-+ strbuf_addstr(&t, "pqr");
-+ strbuf_addbuf(&s, &t);
-+ assert(0 == strcmp("abcpqr", s.buf));
-+
-+ strbuf_release(&s);
-+ strbuf_release(&t);
++ memset(p, (uint8_t)i, hash_size(SHA1_ID));
+}
+
-+int strbuf_test_main(int argc, const char *argv[])
++int strbuf_add_void(void *b, const void *data, size_t sz)
+{
-+ add_test_case("test_strbuf", &test_strbuf);
-+ return test_main(argc, argv);
++ strbuf_add((struct strbuf *)b, data, sz);
++ return sz;
+}
- ## reftable/system.h (new) ##
+ ## reftable/test_framework.h (new) ##
@@
+/*
+Copyright 2020 Google LLC
@@ reftable/system.h (new)
+https://developers.google.com/open-source/licenses/bsd
+*/
+
-+#ifndef SYSTEM_H
-+#define SYSTEM_H
-+
-+#ifndef REFTABLE_STANDALONE
-+
-+#include "git-compat-util.h"
-+#include "cache.h"
-+#include <zlib.h>
-+
-+#else
-+
-+#include <assert.h>
-+#include <errno.h>
-+#include <fcntl.h>
-+#include <inttypes.h>
-+#include <stdint.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <sys/stat.h>
-+#include <sys/time.h>
-+#include <sys/types.h>
-+#include <unistd.h>
-+#include <zlib.h>
++#ifndef TEST_FRAMEWORK_H
++#define TEST_FRAMEWORK_H
+
-+#include "compat.h"
++#include "system.h"
++#include "reftable-error.h"
++
++#define EXPECT_ERR(c) \
++ if (c != 0) { \
++ fflush(stderr); \
++ fflush(stdout); \
++ fprintf(stderr, "%s: %d: error == %d (%s), want 0\n", \
++ __FILE__, __LINE__, c, reftable_error_str(c)); \
++ abort(); \
++ }
+
-+#endif /* REFTABLE_STANDALONE */
++#define EXPECT_STREQ(a, b) \
++ if (strcmp(a, b)) { \
++ fflush(stderr); \
++ fflush(stdout); \
++ fprintf(stderr, "%s:%d: %s (%s) != %s (%s)\n", __FILE__, \
++ __LINE__, #a, a, #b, b); \
++ abort(); \
++ }
+
-+void reftable_clear_dir(const char *dirname);
++#define EXPECT(c) \
++ if (!(c)) { \
++ fflush(stderr); \
++ fflush(stdout); \
++ fprintf(stderr, "%s: %d: failed assertion %s\n", __FILE__, \
++ __LINE__, #c); \
++ abort(); \
++ }
+
-+#define SHA1_ID 0x73686131
-+#define SHA256_ID 0x73323536
-+#define SHA1_SIZE 20
-+#define SHA256_SIZE 32
++void set_test_hash(uint8_t *p, int i);
+
-+/* This is uncompress2, which is only available in zlib as of 2017.
++/* Like strbuf_add, but suitable for passing to reftable_new_writer
+ */
-+int uncompress_return_consumed(Bytef *dest, uLongf *destLen,
-+ const Bytef *source, uLong *sourceLen);
-+int hash_size(uint32_t id);
++int strbuf_add_void(void *b, const void *data, size_t sz);
+
+#endif
@@ t/helper/test-reftable.c (new)
+
+int cmd__reftable(int argc, const char **argv)
+{
-+ strbuf_test_main(argc, argv);
++ basics_test_main(argc, argv);
++
+ return 0;
+}
## t/helper/test-tool.c ##
@@ t/helper/test-tool.c: static struct test_cmd cmds[] = {
+ { "path-utils", cmd__path_utils },
+ { "pkt-line", cmd__pkt_line },
+ { "prio-queue", cmd__prio_queue },
+- { "proc-receive", cmd__proc_receive},
++ { "proc-receive", cmd__proc_receive },
+ { "progress", cmd__progress },
+ { "reach", cmd__reach },
+ { "read-cache", cmd__read_cache },
{ "read-graph", cmd__read_graph },
{ "read-midx", cmd__read_midx },
{ "ref-store", cmd__ref_store },
@@ t/helper/test-tool.h: int cmd__read_cache(int argc, const char **argv);
int cmd__regex(int argc, const char **argv);
int cmd__repository(int argc, const char **argv);
int cmd__revision_walking(int argc, const char **argv);
+
+ ## t/t0032-reftable-unittest.sh (new) ##
+@@
++#!/bin/sh
++#
++# Copyright (c) 2020 Google LLC
++#
++
++test_description='reftable unittests'
++
++. ./test-lib.sh
++
++test_expect_success 'unittests' '
++ test-tool reftable
++'
++
++test_done
4: b94c5f5c61 ! 6: f71e82b995 reftable: add a barebones unittest framework
@@ Metadata
Author: Han-Wen Nienhuys <hanwen@google.com>
## Commit message ##
- reftable: add a barebones unittest framework
+ reftable: add blocksource, an abstraction for random access reads
+
+ The reftable format is usually used with files for storage. However, we abstract
+ away this using the blocksource data structure. This has two advantages:
+
+ * log blocks are zlib compressed, and handling them is simplified if we can
+ discard byte segments from within the block layer.
+
+ * for unittests, it is useful to read and write in-memory. The blocksource
+ allows us to abstract the data away from on-disk files.
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
- ## reftable/test_framework.c (new) ##
+ ## Makefile ##
+@@ Makefile: XDIFF_OBJS += xdiff/xutils.o
+
+ REFTABLE_OBJS += reftable/basics.o
+ REFTABLE_OBJS += reftable/error.o
++REFTABLE_OBJS += reftable/blocksource.o
+ REFTABLE_OBJS += reftable/publicbasics.o
+
+ REFTABLE_TEST_OBJS += reftable/test_framework.o
+
+ ## reftable/blocksource.c (new) ##
@@
+/*
+Copyright 2020 Google LLC
@@ reftable/test_framework.c (new)
+https://developers.google.com/open-source/licenses/bsd
+*/
+
-+#include "test_framework.h"
-+
+#include "system.h"
++
+#include "basics.h"
++#include "blocksource.h"
++#include "reftable-blocksource.h"
++#include "reftable-error.h"
+
-+static struct test_case **test_cases;
-+static int test_case_len;
-+static int test_case_cap;
++static void strbuf_return_block(void *b, struct reftable_block *dest)
++{
++ memset(dest->data, 0xff, dest->len);
++ reftable_free(dest->data);
++}
+
-+static struct test_case *new_test_case(const char *name, void (*testfunc)(void))
++static void strbuf_close(void *b)
+{
-+ struct test_case *tc = reftable_malloc(sizeof(struct test_case));
-+ tc->name = name;
-+ tc->testfunc = testfunc;
-+ return tc;
+}
+
-+struct test_case *add_test_case(const char *name, void (*testfunc)(void))
++static int strbuf_read_block(void *v, struct reftable_block *dest, uint64_t off,
++ uint32_t size)
+{
-+ struct test_case *tc = new_test_case(name, testfunc);
-+ if (test_case_len == test_case_cap) {
-+ test_case_cap = 2 * test_case_cap + 1;
-+ test_cases = reftable_realloc(
-+ test_cases, sizeof(struct test_case) * test_case_cap);
-+ }
++ struct strbuf *b = (struct strbuf *)v;
++ assert(off + size <= b->len);
++ dest->data = reftable_calloc(size);
++ memcpy(dest->data, b->buf + off, size);
++ dest->len = size;
++ return size;
++}
+
-+ test_cases[test_case_len++] = tc;
-+ return tc;
++static uint64_t strbuf_size(void *b)
++{
++ return ((struct strbuf *)b)->len;
+}
+
-+int test_main(int argc, const char *argv[])
++static struct reftable_block_source_vtable strbuf_vtable = {
++ .size = &strbuf_size,
++ .read_block = &strbuf_read_block,
++ .return_block = &strbuf_return_block,
++ .close = &strbuf_close,
++};
++
++void block_source_from_strbuf(struct reftable_block_source *bs,
++ struct strbuf *buf)
+{
-+ const char *filter = NULL;
-+ int i = 0;
-+ if (argc > 1) {
-+ filter = argv[1];
-+ }
++ assert(bs->ops == NULL);
++ bs->ops = &strbuf_vtable;
++ bs->arg = buf;
++}
+
-+ for (i = 0; i < test_case_len; i++) {
-+ const char *name = test_cases[i]->name;
-+ if (filter == NULL || strstr(name, filter) != NULL) {
-+ printf("case %s\n", name);
-+ test_cases[i]->testfunc();
-+ } else {
-+ printf("skip %s\n", name);
-+ }
++static void malloc_return_block(void *b, struct reftable_block *dest)
++{
++ memset(dest->data, 0xff, dest->len);
++ reftable_free(dest->data);
++}
++
++static struct reftable_block_source_vtable malloc_vtable = {
++ .return_block = &malloc_return_block,
++};
++
++static struct reftable_block_source malloc_block_source_instance = {
++ .ops = &malloc_vtable,
++};
+
-+ reftable_free(test_cases[i]);
++struct reftable_block_source malloc_block_source(void)
++{
++ return malloc_block_source_instance;
++}
++
++struct file_block_source {
++ int fd;
++ uint64_t size;
++};
++
++static uint64_t file_size(void *b)
++{
++ return ((struct file_block_source *)b)->size;
++}
++
++static void file_return_block(void *b, struct reftable_block *dest)
++{
++ memset(dest->data, 0xff, dest->len);
++ reftable_free(dest->data);
++}
++
++static void file_close(void *b)
++{
++ int fd = ((struct file_block_source *)b)->fd;
++ if (fd > 0) {
++ close(fd);
++ ((struct file_block_source *)b)->fd = 0;
+ }
-+ reftable_free(test_cases);
-+ test_cases = NULL;
-+ test_case_len = 0;
-+ test_case_cap = 0;
-+ return 0;
++
++ reftable_free(b);
+}
+
-+void set_test_hash(uint8_t *p, int i)
++static int file_read_block(void *v, struct reftable_block *dest, uint64_t off,
++ uint32_t size)
+{
-+ memset(p, (uint8_t)i, hash_size(SHA1_ID));
++ struct file_block_source *b = (struct file_block_source *)v;
++ assert(off + size <= b->size);
++ dest->data = reftable_malloc(size);
++ if (pread(b->fd, dest->data, size, off) != size)
++ return -1;
++ dest->len = size;
++ return size;
++}
++
++static struct reftable_block_source_vtable file_vtable = {
++ .size = &file_size,
++ .read_block = &file_read_block,
++ .return_block = &file_return_block,
++ .close = &file_close,
++};
++
++int reftable_block_source_from_file(struct reftable_block_source *bs,
++ const char *name)
++{
++ struct stat st = { 0 };
++ int err = 0;
++ int fd = open(name, O_RDONLY);
++ struct file_block_source *p = NULL;
++ if (fd < 0) {
++ if (errno == ENOENT) {
++ return REFTABLE_NOT_EXIST_ERROR;
++ }
++ return -1;
++ }
++
++ err = fstat(fd, &st);
++ if (err < 0)
++ return -1;
++
++ p = reftable_calloc(sizeof(struct file_block_source));
++ p->size = st.st_size;
++ p->fd = fd;
++
++ assert(bs->ops == NULL);
++ bs->ops = &file_vtable;
++ bs->arg = p;
++ return 0;
+}
- ## reftable/test_framework.h (new) ##
+ ## reftable/blocksource.h (new) ##
@@
+/*
+Copyright 2020 Google LLC
@@ reftable/test_framework.h (new)
+https://developers.google.com/open-source/licenses/bsd
+*/
+
-+#ifndef TEST_FRAMEWORK_H
-+#define TEST_FRAMEWORK_H
++#ifndef BLOCKSOURCE_H
++#define BLOCKSOURCE_H
+
+#include "system.h"
+
-+#ifdef NDEBUG
-+#undef NDEBUG
-+#endif
++struct reftable_block_source;
++
++/* Create an in-memory block source for reading reftables */
++void block_source_from_strbuf(struct reftable_block_source *bs,
++ struct strbuf *buf);
++
++struct reftable_block_source malloc_block_source(void);
+
-+#ifdef assert
-+#undef assert
+#endif
+
+ ## reftable/reftable-blocksource.h (new) ##
+@@
++/*
++Copyright 2020 Google LLC
+
-+#define assert_err(c) \
-+ if (c != 0) { \
-+ fflush(stderr); \
-+ fflush(stdout); \
-+ fprintf(stderr, "%s: %d: error == %d (%s), want 0\n", \
-+ __FILE__, __LINE__, c, reftable_error_str(c)); \
-+ abort(); \
-+ }
++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
++*/
+
-+#define assert_streq(a, b) \
-+ if (strcmp(a, b)) { \
-+ fflush(stderr); \
-+ fflush(stdout); \
-+ fprintf(stderr, "%s:%d: %s (%s) != %s (%s)\n", __FILE__, \
-+ __LINE__, #a, a, #b, b); \
-+ abort(); \
-+ }
++#ifndef REFTABLE_BLOCKSOURCE_H
++#define REFTABLE_BLOCKSOURCE_H
+
-+#define assert(c) \
-+ if (!(c)) { \
-+ fflush(stderr); \
-+ fflush(stdout); \
-+ fprintf(stderr, "%s: %d: failed assertion %s\n", __FILE__, \
-+ __LINE__, #c); \
-+ abort(); \
-+ }
++#include <stdint.h>
++
++/* block_source is a generic wrapper for a seekable readable file.
++ */
++struct reftable_block_source {
++ struct reftable_block_source_vtable *ops;
++ void *arg;
++};
+
-+struct test_case {
-+ const char *name;
-+ void (*testfunc)(void);
++/* a contiguous segment of bytes. It keeps track of its generating block_source
++ so it can return itself into the pool.
++*/
++struct reftable_block {
++ uint8_t *data;
++ int len;
++ struct reftable_block_source source;
+};
+
-+struct test_case *add_test_case(const char *name, void (*testfunc)(void));
-+int test_main(int argc, const char *argv[]);
++/* block_source_vtable are the operations that make up block_source */
++struct reftable_block_source_vtable {
++ /* returns the size of a block source */
++ uint64_t (*size)(void *source);
++
++ /* reads a segment from the block source. It is an error to read
++ beyond the end of the block */
++ int (*read_block)(void *source, struct reftable_block *dest,
++ uint64_t off, uint32_t size);
++ /* mark the block as read; may return the data back to malloc */
++ void (*return_block)(void *source, struct reftable_block *blockp);
++
++ /* release all resources associated with the block source */
++ void (*close)(void *source);
++};
+
-+void set_test_hash(uint8_t *p, int i);
++/* opens a file on the file system as a block_source */
++int reftable_block_source_from_file(struct reftable_block_source *block_src,
++ const char *name);
+
+#endif
6: 8eb944ea9b ! 7: bbe2ed7173 reftable: (de)serialization for the polymorphic record type.
@@ Metadata
## Commit message ##
reftable: (de)serialization for the polymorphic record type.
+ The reftable format is structured as a sequence of blocks, and each block
+ contains a sequence of prefix-compressed key-value records. There are 4 types of
+ records, and they have similarities in how they must be handled. This is
+ achieved by introducing a polymorphic 'record' type that encapsulates ref, log,
+ index and object records.
+
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
## Makefile ##
@@ Makefile: REFTABLE_OBJS += reftable/basics.o
+ REFTABLE_OBJS += reftable/error.o
REFTABLE_OBJS += reftable/blocksource.o
REFTABLE_OBJS += reftable/publicbasics.o
- REFTABLE_OBJS += reftable/compat.o
+REFTABLE_OBJS += reftable/record.o
- REFTABLE_OBJS += reftable/strbuf.o
+REFTABLE_TEST_OBJS += reftable/record_test.o
- REFTABLE_TEST_OBJS += reftable/strbuf_test.o
REFTABLE_TEST_OBJS += reftable/test_framework.o
+ REFTABLE_TEST_OBJS += reftable/basics_test.o
## reftable/constants.h (new) ##
@@ reftable/record.c (new)
+
+#include "system.h"
+#include "constants.h"
-+#include "reftable.h"
++#include "reftable-error.h"
+#include "basics.h"
+
+int get_var_int(uint64_t *dest, struct string_view *in)
@@ reftable/record.c (new)
+
+ /* This is simple and correct, but we could probably reuse the hash
+ fields. */
-+ reftable_ref_record_clear(ref);
++ reftable_ref_record_release(ref);
+ if (src->refname != NULL) {
+ ref->refname = xstrdup(src->refname);
+ }
@@ reftable/record.c (new)
+ printf("}\n");
+}
+
-+static void reftable_ref_record_clear_void(void *rec)
++static void reftable_ref_record_release_void(void *rec)
+{
-+ reftable_ref_record_clear((struct reftable_ref_record *)rec);
++ reftable_ref_record_release((struct reftable_ref_record *)rec);
+}
+
-+void reftable_ref_record_clear(struct reftable_ref_record *ref)
++void reftable_ref_record_release(struct reftable_ref_record *ref)
+{
+ reftable_free(ref->refname);
+ reftable_free(ref->target);
@@ reftable/record.c (new)
+ .val_type = &reftable_ref_record_val_type,
+ .encode = &reftable_ref_record_encode,
+ .decode = &reftable_ref_record_decode,
-+ .clear = &reftable_ref_record_clear_void,
++ .release = &reftable_ref_record_release_void,
+ .is_deletion = &reftable_ref_record_is_deletion_void,
+};
+
@@ reftable/record.c (new)
+ strbuf_add(dest, rec->hash_prefix, rec->hash_prefix_len);
+}
+
-+static void reftable_obj_record_clear(void *rec)
++static void reftable_obj_record_release(void *rec)
+{
+ struct reftable_obj_record *obj = (struct reftable_obj_record *)rec;
+ FREE_AND_NULL(obj->hash_prefix);
@@ reftable/record.c (new)
+ (const struct reftable_obj_record *)src_rec;
+ int olen;
+
-+ reftable_obj_record_clear(obj);
++ reftable_obj_record_release(obj);
+ *obj = *src;
+ obj->hash_prefix = reftable_malloc(obj->hash_prefix_len);
+ memcpy(obj->hash_prefix, src->hash_prefix, obj->hash_prefix_len);
@@ reftable/record.c (new)
+ .val_type = &reftable_obj_record_val_type,
+ .encode = &reftable_obj_record_encode,
+ .decode = &reftable_obj_record_decode,
-+ .clear = &reftable_obj_record_clear,
++ .release = &reftable_obj_record_release,
+ .is_deletion = not_a_deletion,
+};
+
@@ reftable/record.c (new)
+ const struct reftable_log_record *src =
+ (const struct reftable_log_record *)src_rec;
+
-+ reftable_log_record_clear(dst);
++ reftable_log_record_release(dst);
+ *dst = *src;
+ if (dst->refname != NULL) {
+ dst->refname = xstrdup(dst->refname);
@@ reftable/record.c (new)
+ }
+}
+
-+static void reftable_log_record_clear_void(void *rec)
++static void reftable_log_record_release_void(void *rec)
+{
+ struct reftable_log_record *r = (struct reftable_log_record *)rec;
-+ reftable_log_record_clear(r);
++ reftable_log_record_release(r);
+}
+
-+void reftable_log_record_clear(struct reftable_log_record *r)
++void reftable_log_record_release(struct reftable_log_record *r)
+{
+ reftable_free(r->refname);
+ reftable_free(r->new_hash);
@@ reftable/record.c (new)
+ .val_type = &reftable_log_record_val_type,
+ .encode = &reftable_log_record_encode,
+ .decode = &reftable_log_record_decode,
-+ .clear = &reftable_log_record_clear_void,
++ .release = &reftable_log_record_release_void,
+ .is_deletion = &reftable_log_record_is_deletion_void,
+};
+
@@ reftable/record.c (new)
+
+void reftable_record_destroy(struct reftable_record *rec)
+{
-+ reftable_record_clear(rec);
++ reftable_record_release(rec);
+ reftable_free(reftable_record_yield(rec));
+}
+
@@ reftable/record.c (new)
+ dst->offset = src->offset;
+}
+
-+static void reftable_index_record_clear(void *rec)
++static void reftable_index_record_release(void *rec)
+{
+ struct reftable_index_record *idx = (struct reftable_index_record *)rec;
+ strbuf_release(&idx->last_key);
@@ reftable/record.c (new)
+ .val_type = &reftable_index_record_val_type,
+ .encode = &reftable_index_record_encode,
+ .decode = &reftable_index_record_decode,
-+ .clear = &reftable_index_record_clear,
++ .release = &reftable_index_record_release,
+ .is_deletion = ¬_a_deletion,
+};
+
@@ reftable/record.c (new)
+ return rec->ops->decode(rec->data, key, extra, src, hash_size);
+}
+
-+void reftable_record_clear(struct reftable_record *rec)
++void reftable_record_release(struct reftable_record *rec)
+{
-+ rec->ops->clear(rec->data);
++ rec->ops->release(rec->data);
+}
+
+int reftable_record_is_deletion(struct reftable_record *rec)
@@ reftable/record.h (new)
+#ifndef RECORD_H
+#define RECORD_H
+
-+#include "reftable.h"
-+#include "strbuf.h"
+#include "system.h"
+
++#include <stdint.h>
++
++#include "reftable-record.h"
++
+/*
+ A substring of existing string data. This structure takes no responsibility
+ for the lifetime of the data it points to.
@@ reftable/record.h (new)
+ struct string_view src, int hash_size);
+
+ /* deallocate and null the record. */
-+ void (*clear)(void *rec);
++ void (*release)(void *rec);
+
+ /* is this a tombstone? */
+ int (*is_deletion)(const void *rec);
@@ reftable/record.h (new)
+int reftable_record_is_deletion(struct reftable_record *rec);
+
+/* zeroes out the embedded record */
-+void reftable_record_clear(struct reftable_record *rec);
++void reftable_record_release(struct reftable_record *rec);
+
+/* clear and deallocate embedded record, and zero `rec`. */
+void reftable_record_destroy(struct reftable_record *rec);
@@ reftable/record_test.c (new)
+#include "system.h"
+#include "basics.h"
+#include "constants.h"
-+#include "reftable.h"
+#include "test_framework.h"
+#include "reftable-tests.h"
+
@@ reftable/record_test.c (new)
+ reftable_record_copy_from(©, rec, SHA1_SIZE);
+ switch (reftable_record_type(©)) {
+ case BLOCK_TYPE_REF:
-+ assert(reftable_ref_record_equal(reftable_record_as_ref(©),
++ EXPECT(reftable_ref_record_equal(reftable_record_as_ref(©),
+ reftable_record_as_ref(rec),
+ SHA1_SIZE));
+ break;
+ case BLOCK_TYPE_LOG:
-+ assert(reftable_log_record_equal(reftable_record_as_log(©),
++ EXPECT(reftable_log_record_equal(reftable_record_as_log(©),
+ reftable_record_as_log(rec),
+ SHA1_SIZE));
+ break;
@@ reftable/record_test.c (new)
+ int n = put_var_int(&out, in);
+ uint64_t got = 0;
+
-+ assert(n > 0);
++ EXPECT(n > 0);
+ out.len = n;
+ n = get_var_int(&got, &out);
-+ assert(n > 0);
++ EXPECT(n > 0);
+
-+ assert(got == in);
++ EXPECT(got == in);
+ }
+}
+
@@ reftable/record_test.c (new)
+ struct strbuf b = STRBUF_INIT;
+ strbuf_addstr(&a, cases[i].a);
+ strbuf_addstr(&b, cases[i].b);
-+ assert(common_prefix_size(&a, &b) == cases[i].want);
++ EXPECT(common_prefix_size(&a, &b) == cases[i].want);
+
+ strbuf_release(&a);
+ strbuf_release(&b);
@@ reftable/record_test.c (new)
+ reftable_record_from_ref(&rec, &in);
+ test_copy(&rec);
+
-+ assert(reftable_record_val_type(&rec) == i);
++ EXPECT(reftable_record_val_type(&rec) == i);
+
+ reftable_record_key(&rec, &key);
+ n = reftable_record_encode(&rec, dest, SHA1_SIZE);
-+ assert(n > 0);
++ EXPECT(n > 0);
+
+ /* decode into a non-zero reftable_record to test for leaks. */
+
+ reftable_record_from_ref(&rec_out, &out);
+ m = reftable_record_decode(&rec_out, key, i, dest, SHA1_SIZE);
-+ assert(n == m);
++ EXPECT(n == m);
+
-+ assert((out.value != NULL) == (in.value != NULL));
-+ assert((out.target_value != NULL) == (in.target_value != NULL));
-+ assert((out.target != NULL) == (in.target != NULL));
-+ reftable_record_clear(&rec_out);
++ EXPECT((out.value != NULL) == (in.value != NULL));
++ EXPECT((out.target_value != NULL) == (in.target_value != NULL));
++ EXPECT((out.target != NULL) == (in.target != NULL));
++ reftable_record_release(&rec_out);
+
+ strbuf_release(&key);
-+ reftable_ref_record_clear(&in);
++ reftable_ref_record_release(&in);
+ }
+}
+
@@ reftable/record_test.c (new)
+ }
+ };
+
-+ assert(!reftable_log_record_equal(&in[0], &in[1], SHA1_SIZE));
++ EXPECT(!reftable_log_record_equal(&in[0], &in[1], SHA1_SIZE));
+ in[1].update_index = in[0].update_index;
-+ assert(reftable_log_record_equal(&in[0], &in[1], SHA1_SIZE));
-+ reftable_log_record_clear(&in[0]);
-+ reftable_log_record_clear(&in[1]);
++ EXPECT(reftable_log_record_equal(&in[0], &in[1], SHA1_SIZE));
++ reftable_log_record_release(&in[0]);
++ reftable_log_record_release(&in[1]);
+}
+
+static void test_reftable_log_record_roundtrip(void)
@@ reftable/record_test.c (new)
+ reftable_record_key(&rec, &key);
+
+ n = reftable_record_encode(&rec, dest, SHA1_SIZE);
-+ assert(n >= 0);
++ EXPECT(n >= 0);
+ reftable_record_from_log(&rec_out, &out);
+ valtype = reftable_record_val_type(&rec);
+ m = reftable_record_decode(&rec_out, key, valtype, dest,
+ SHA1_SIZE);
-+ assert(n == m);
++ EXPECT(n == m);
+
-+ assert(reftable_log_record_equal(&in[i], &out, SHA1_SIZE));
-+ reftable_log_record_clear(&in[i]);
++ EXPECT(reftable_log_record_equal(&in[i], &out, SHA1_SIZE));
++ reftable_log_record_release(&in[i]);
+ strbuf_release(&key);
-+ reftable_record_clear(&rec_out);
++ reftable_record_release(&rec_out);
+ }
+}
+
@@ reftable/record_test.c (new)
+ uint32_t out;
+ put_be24(dest, in);
+ out = get_be24(dest);
-+ assert(in == out);
++ EXPECT(in == out);
+}
+
+static void test_key_roundtrip(void)
@@ reftable/record_test.c (new)
+ strbuf_addstr(&key, "refs/tags/bla");
+ extra = 6;
+ n = reftable_encode_key(&restart, dest, last_key, key, extra);
-+ assert(!restart);
-+ assert(n > 0);
++ EXPECT(!restart);
++ EXPECT(n > 0);
+
+ m = reftable_decode_key(&roundtrip, &rt_extra, last_key, dest);
-+ assert(n == m);
-+ assert(0 == strbuf_cmp(&key, &roundtrip));
-+ assert(rt_extra == extra);
++ EXPECT(n == m);
++ EXPECT(0 == strbuf_cmp(&key, &roundtrip));
++ EXPECT(rt_extra == extra);
+
+ strbuf_release(&last_key);
+ strbuf_release(&key);
@@ reftable/record_test.c (new)
+ test_copy(&rec);
+ reftable_record_key(&rec, &key);
+ n = reftable_record_encode(&rec, dest, SHA1_SIZE);
-+ assert(n > 0);
++ EXPECT(n > 0);
+ extra = reftable_record_val_type(&rec);
+ reftable_record_from_obj(&rec_out, &out);
+ m = reftable_record_decode(&rec_out, key, extra, dest,
+ SHA1_SIZE);
-+ assert(n == m);
++ EXPECT(n == m);
+
-+ assert(in.hash_prefix_len == out.hash_prefix_len);
-+ assert(in.offset_len == out.offset_len);
++ EXPECT(in.hash_prefix_len == out.hash_prefix_len);
++ EXPECT(in.offset_len == out.offset_len);
+
-+ assert(!memcmp(in.hash_prefix, out.hash_prefix,
++ EXPECT(!memcmp(in.hash_prefix, out.hash_prefix,
+ in.hash_prefix_len));
-+ assert(0 == memcmp(in.offsets, out.offsets,
++ EXPECT(0 == memcmp(in.offsets, out.offsets,
+ sizeof(uint64_t) * in.offset_len));
+ strbuf_release(&key);
-+ reftable_record_clear(&rec_out);
++ reftable_record_release(&rec_out);
+ }
+}
+
@@ reftable/record_test.c (new)
+ reftable_record_key(&rec, &key);
+ test_copy(&rec);
+
-+ assert(0 == strbuf_cmp(&key, &in.last_key));
++ EXPECT(0 == strbuf_cmp(&key, &in.last_key));
+ n = reftable_record_encode(&rec, dest, SHA1_SIZE);
-+ assert(n > 0);
++ EXPECT(n > 0);
+
+ extra = reftable_record_val_type(&rec);
+ reftable_record_from_index(&out_rec, &out);
+ m = reftable_record_decode(&out_rec, key, extra, dest, SHA1_SIZE);
-+ assert(m == n);
++ EXPECT(m == n);
+
-+ assert(in.offset == out.offset);
++ EXPECT(in.offset == out.offset);
+
-+ reftable_record_clear(&out_rec);
++ reftable_record_release(&out_rec);
+ strbuf_release(&key);
+ strbuf_release(&in.last_key);
+}
+
+int record_test_main(int argc, const char *argv[])
+{
-+ add_test_case("test_reftable_log_record_equal",
-+ &test_reftable_log_record_equal);
-+ add_test_case("test_reftable_log_record_roundtrip",
-+ &test_reftable_log_record_roundtrip);
-+ add_test_case("test_reftable_ref_record_roundtrip",
-+ &test_reftable_ref_record_roundtrip);
-+ add_test_case("test_varint_roundtrip", &test_varint_roundtrip);
-+ add_test_case("test_key_roundtrip", &test_key_roundtrip);
-+ add_test_case("test_common_prefix", &test_common_prefix);
-+ add_test_case("test_reftable_obj_record_roundtrip",
-+ &test_reftable_obj_record_roundtrip);
-+ add_test_case("test_reftable_index_record_roundtrip",
-+ &test_reftable_index_record_roundtrip);
-+ add_test_case("test_u24_roundtrip", &test_u24_roundtrip);
-+ return test_main(argc, 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();
++ return 0;
+}
+ ## reftable/reftable-record.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 REFTABLE_RECORD_H
++#define REFTABLE_RECORD_H
++
++#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.
++*/
++
++/* 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. */
++};
++
++/* 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 */
++void reftable_ref_record_print(struct reftable_ref_record *ref,
++ uint32_t hash_id);
++
++/* frees and nulls all pointer values. */
++void reftable_ref_record_release(struct reftable_ref_record *ref);
++
++/* returns whether two reftable_ref_records are the same */
++int reftable_ref_record_equal(struct reftable_ref_record *a,
++ struct reftable_ref_record *b, int hash_size);
++
++/* reftable_log_record holds a reflog entry */
++struct reftable_log_record {
++ char *refname;
++ uint64_t update_index; /* logical timestamp of a transactional update.
++ */
++ uint8_t *new_hash;
++ uint8_t *old_hash;
++ char *name;
++ char *email;
++ uint64_t time;
++ int16_t tz_offset;
++ char *message;
++};
++
++/* returns whether 'ref' represents the deletion of a log record. */
++int reftable_log_record_is_deletion(const struct reftable_log_record *log);
++
++/* frees and nulls all pointer values. */
++void reftable_log_record_release(struct reftable_log_record *log);
++
++/* returns whether two records are equal. Useful for testing. */
++int reftable_log_record_equal(struct reftable_log_record *a,
++ struct reftable_log_record *b, int hash_size);
++
++/* dumps a reftable_log_record on stdout, for debugging/testing. */
++void reftable_log_record_print(struct reftable_log_record *log,
++ uint32_t hash_id);
++
++#endif
+
## t/helper/test-reftable.c ##
@@
-
int cmd__reftable(int argc, const char **argv)
{
+ basics_test_main(argc, argv);
+-
+ record_test_main(argc, argv);
- strbuf_test_main(argc, argv);
return 0;
}
7: 757dd30fe2 ! 8: a358b052d5 reftable: reading/writing blocks
@@ Metadata
## Commit message ##
reftable: reading/writing blocks
+ The reftable format is structured as a sequence of block. Within a block,
+ records are prefix compressed, with an index of offsets for fully expand keys to
+ enable binary search within blocks.
+
+ This commit provides the logic to read and write these blocks.
+
Includes a code snippet copied from zlib
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
## Makefile ##
-@@ Makefile: XDIFF_OBJS += xdiff/xprepare.o
- XDIFF_OBJS += xdiff/xutils.o
+@@ Makefile: XDIFF_OBJS += xdiff/xutils.o
REFTABLE_OBJS += reftable/basics.o
+ REFTABLE_OBJS += reftable/error.o
+REFTABLE_OBJS += reftable/block.o
REFTABLE_OBJS += reftable/blocksource.o
REFTABLE_OBJS += reftable/publicbasics.o
- REFTABLE_OBJS += reftable/compat.o
REFTABLE_OBJS += reftable/record.o
- REFTABLE_OBJS += reftable/strbuf.o
+REFTABLE_OBJS += reftable/zlib-compat.o
+REFTABLE_TEST_OBJS += reftable/block_test.o
REFTABLE_TEST_OBJS += reftable/record_test.o
- REFTABLE_TEST_OBJS += reftable/strbuf_test.o
REFTABLE_TEST_OBJS += reftable/test_framework.o
+ REFTABLE_TEST_OBJS += reftable/basics_test.o
## reftable/.gitattributes (new) ##
@@
@@ reftable/block.c (new)
+#include "blocksource.h"
+#include "constants.h"
+#include "record.h"
-+#include "reftable.h"
++#include "reftable-error.h"
+#include "system.h"
+#include "zlib.h"
+
@@ reftable/block.c (new)
+ return -1;
+}
+
-+
+int block_writer_finish(struct block_writer *w)
+{
+ int i = 0;
@@ reftable/block.c (new)
+ return err;
+}
+
-+void block_writer_clear(struct block_writer *bw)
++void block_writer_release(struct block_writer *bw)
+{
+ FREE_AND_NULL(bw->restarts);
+ strbuf_release(&bw->last_key);
@@ reftable/block.h (new)
+
+#include "basics.h"
+#include "record.h"
-+#include "reftable.h"
++#include "reftable-blocksource.h"
+
+/*
+ Writes reftable blocks. The block_writer is reused across blocks to minimize
@@ reftable/block.h (new)
+int block_writer_finish(struct block_writer *w);
+
+/* clears out internally allocated block_writer members. */
-+void block_writer_clear(struct block_writer *bw);
++void block_writer_release(struct block_writer *bw);
+
+/* Read a block. */
+struct block_reader {
@@ reftable/block_test.c (new)
+#include "basics.h"
+#include "constants.h"
+#include "record.h"
-+#include "reftable.h"
+#include "test_framework.h"
+#include "reftable-tests.h"
+
-+struct binsearch_args {
-+ int key;
-+ int *arr;
-+};
-+
-+static int binsearch_func(size_t i, void *void_args)
-+{
-+ struct binsearch_args *args = (struct binsearch_args *)void_args;
-+
-+ return args->key < args->arr[i];
-+}
-+
-+static void test_binsearch(void)
-+{
-+ int arr[] = { 2, 4, 6, 8, 10 };
-+ size_t sz = ARRAY_SIZE(arr);
-+ struct binsearch_args args = {
-+ .arr = arr,
-+ };
-+
-+ int i = 0;
-+ for (i = 1; i < 11; i++) {
-+ int res;
-+ args.key = i;
-+ res = binsearch(sz, &binsearch_func, &args);
-+
-+ if (res < sz) {
-+ assert(args.key < arr[res]);
-+ if (res > 0) {
-+ assert(args.key >= arr[res - 1]);
-+ }
-+ } else {
-+ assert(args.key == 10 || args.key == 11);
-+ }
-+ }
-+}
-+
+static void test_block_read_write(void)
+{
+ const int header_off = 21; /* random */
@@ reftable/block_test.c (new)
+ n = block_writer_add(&bw, &rec);
+ ref.refname = NULL;
+ ref.value = NULL;
-+ assert(n == 0);
++ EXPECT(n == 0);
+ }
+
+ n = block_writer_finish(&bw);
-+ assert(n > 0);
++ EXPECT(n > 0);
+
-+ block_writer_clear(&bw);
++ block_writer_release(&bw);
+
+ block_reader_init(&br, &block, header_off, block_size, SHA1_SIZE);
+
@@ reftable/block_test.c (new)
+
+ while (1) {
+ int r = block_iter_next(&it, &rec);
-+ assert(r >= 0);
++ EXPECT(r >= 0);
+ if (r > 0) {
+ break;
+ }
-+ assert_streq(names[j], ref.refname);
++ EXPECT_STREQ(names[j], ref.refname);
+ j++;
+ }
+
-+ reftable_record_clear(&rec);
++ reftable_record_release(&rec);
+ block_iter_close(&it);
+
+ for (i = 0; i < N; i++) {
@@ reftable/block_test.c (new)
+ strbuf_addstr(&want, names[i]);
+
+ n = block_reader_seek(&br, &it, &want);
-+ assert(n == 0);
++ EXPECT(n == 0);
+
+ n = block_iter_next(&it, &rec);
-+ assert(n == 0);
++ EXPECT(n == 0);
+
-+ assert_streq(names[i], ref.refname);
++ EXPECT_STREQ(names[i], ref.refname);
+
+ want.len--;
+ n = block_reader_seek(&br, &it, &want);
-+ assert(n == 0);
++ EXPECT(n == 0);
+
+ n = block_iter_next(&it, &rec);
-+ assert(n == 0);
-+ assert_streq(names[10 * (i / 10)], ref.refname);
++ EXPECT(n == 0);
++ EXPECT_STREQ(names[10 * (i / 10)], ref.refname);
+
+ block_iter_close(&it);
+ }
+
-+ reftable_record_clear(&rec);
++ reftable_record_release(&rec);
+ reftable_block_done(&br.block);
+ strbuf_release(&want);
+ for (i = 0; i < N; i++) {
@@ reftable/block_test.c (new)
+
+int block_test_main(int argc, const char *argv[])
+{
-+ add_test_case("binsearch", &test_binsearch);
-+ add_test_case("block_read_write", &test_block_read_write);
-+ return test_main(argc, argv);
++ test_block_read_write();
++ return 0;
+}
## reftable/zlib-compat.c (new) ##
@@ reftable/zlib-compat.c (new)
## t/helper/test-reftable.c ##
@@
-
int cmd__reftable(int argc, const char **argv)
{
+ basics_test_main(argc, argv);
+ block_test_main(argc, argv);
record_test_main(argc, argv);
- strbuf_test_main(argc, argv);
return 0;
+ }
8: e30a7e0281 ! 9: 24afac9c91 reftable: a generic binary tree implementation
@@ Metadata
## Commit message ##
reftable: a generic binary tree implementation
- This is necessary for building a OID => ref map on write
+ The reftable format includes support for an (OID => ref) map. This map can speed
+ up visibility and reachability checks. In particular, various operations along
+ the fetch/push path within Gerrit have ben sped up by using this structure.
+
+ The map is constructed with help of a binary tree. Object IDs are hashes, so
+ they are uniformly distributed. Hence, the tree does not attempt forced
+ rebalancing.
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
## Makefile ##
-@@ Makefile: REFTABLE_OBJS += reftable/publicbasics.o
- REFTABLE_OBJS += reftable/compat.o
+@@ Makefile: REFTABLE_OBJS += reftable/block.o
+ REFTABLE_OBJS += reftable/blocksource.o
+ REFTABLE_OBJS += reftable/publicbasics.o
REFTABLE_OBJS += reftable/record.o
- REFTABLE_OBJS += reftable/strbuf.o
+REFTABLE_OBJS += reftable/tree.o
REFTABLE_OBJS += reftable/zlib-compat.o
++REFTABLE_TEST_OBJS += reftable/basics_test.o
REFTABLE_TEST_OBJS += reftable/block_test.o
REFTABLE_TEST_OBJS += reftable/record_test.o
- REFTABLE_TEST_OBJS += reftable/strbuf_test.o
REFTABLE_TEST_OBJS += reftable/test_framework.o
+-REFTABLE_TEST_OBJS += reftable/basics_test.o
+REFTABLE_TEST_OBJS += reftable/tree_test.o
TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
@@ reftable/tree_test.c (new)
+
+#include "basics.h"
+#include "record.h"
-+#include "reftable.h"
+#include "test_framework.h"
+#include "reftable-tests.h"
+
@@ reftable/tree_test.c (new)
+
+int tree_test_main(int argc, const char *argv[])
+{
-+ add_test_case("test_tree", &test_tree);
-+ return test_main(argc, argv);
++ test_tree();
++ return 0;
+}
## t/helper/test-reftable.c ##
@@ t/helper/test-reftable.c: int cmd__reftable(int argc, const char **argv)
+ basics_test_main(argc, argv);
block_test_main(argc, argv);
record_test_main(argc, argv);
- strbuf_test_main(argc, argv);
+ tree_test_main(argc, argv);
return 0;
}
9: 68aee16e60 ! 10: 5f0b7c5592 reftable: write reftable files
@@ Commit message
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
## Makefile ##
-@@ Makefile: REFTABLE_OBJS += reftable/compat.o
+@@ Makefile: REFTABLE_OBJS += reftable/blocksource.o
+ REFTABLE_OBJS += reftable/publicbasics.o
REFTABLE_OBJS += reftable/record.o
- REFTABLE_OBJS += reftable/strbuf.o
REFTABLE_OBJS += reftable/tree.o
+REFTABLE_OBJS += reftable/writer.o
REFTABLE_OBJS += reftable/zlib-compat.o
- REFTABLE_TEST_OBJS += reftable/block_test.o
+ REFTABLE_TEST_OBJS += reftable/basics_test.o
+
+ ## reftable/reftable-writer.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 REFTABLE_WRITER_H
++#define REFTABLE_WRITER_H
++
++#include <stdint.h>
++
++#include "reftable-record.h"
++
++/*
++ Writing single reftables
++*/
++
++/* reftable_write_options sets options for writing a single reftable. */
++struct reftable_write_options {
++ /* boolean: do not pad out blocks to block size. */
++ unsigned unpadded : 1;
++
++ /* the blocksize. Should be less than 2^24. */
++ uint32_t block_size;
++
++ /* boolean: do not generate a SHA1 => ref index. */
++ unsigned skip_index_objects : 1;
++
++ /* how often to write complete keys in each block. */
++ int restart_interval;
++
++ /* 4-byte identifier ("sha1", "s256") of the hash.
++ * Defaults to SHA1 if unset
++ */
++ uint32_t hash_id;
++
++ /* boolean: do not check ref names for validity or dir/file conflicts.
++ */
++ unsigned skip_name_check : 1;
++
++ /* boolean: copy log messages exactly. If unset, check that the message
++ * is a single line, and add '\n' if missing.
++ */
++ unsigned exact_log_message : 1;
++};
++
++/* reftable_block_stats holds statistics for a single block type */
++struct reftable_block_stats {
++ /* total number of entries written */
++ int entries;
++ /* total number of key restarts */
++ int restarts;
++ /* total number of blocks */
++ int blocks;
++ /* total number of index blocks */
++ int index_blocks;
++ /* depth of the index */
++ int max_index_level;
++
++ /* offset of the first block for this type */
++ uint64_t offset;
++ /* offset of the top level index block for this type, or 0 if not
++ * present */
++ uint64_t index_offset;
++};
++
++/* stats holds overall statistics for a single reftable */
++struct reftable_stats {
++ /* total number of blocks written. */
++ int blocks;
++ /* stats for ref data */
++ struct reftable_block_stats ref_stats;
++ /* stats for the SHA1 to ref map. */
++ struct reftable_block_stats obj_stats;
++ /* stats for index blocks */
++ struct reftable_block_stats idx_stats;
++ /* stats for log blocks */
++ struct reftable_block_stats log_stats;
++
++ /* disambiguation length of shortened object IDs. */
++ int object_id_len;
++};
++
++/* reftable_new_writer creates a new writer */
++struct reftable_writer *
++reftable_new_writer(int (*writer_func)(void *, const void *, size_t),
++ void *writer_arg, struct reftable_write_options *opts);
++
++/* Set the range of update indices for the records we will add. When writing a
++ table into a stack, the min should be at least
++ reftable_stack_next_update_index(), or REFTABLE_API_ERROR is returned.
++
++ For transactional updates to a stack, typically min==max, and the
++ update_index can be obtained by inspeciting the stack. When converting an
++ existing ref database into a single reftable, this would be a range of
++ update-index timestamps.
++ */
++void reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
++ uint64_t max);
++
++/*
++ Add a reftable_ref_record. The record should have names that come after
++ already added records.
++
++ The update_index must be within the limits set by
++ reftable_writer_set_limits(), or REFTABLE_API_ERROR is returned. It is an
++ REFTABLE_API_ERROR error to write a ref record after a log record.
++*/
++int reftable_writer_add_ref(struct reftable_writer *w,
++ struct reftable_ref_record *ref);
++
++/*
++ Convenience function to add multiple reftable_ref_records; the function sorts
++ the records before adding them, reordering the records array passed in.
++*/
++int reftable_writer_add_refs(struct reftable_writer *w,
++ struct reftable_ref_record *refs, int n);
++
++/*
++ adds reftable_log_records. Log records are keyed by (refname, decreasing
++ update_index). The key for the record added must come after the already added
++ log records.
++*/
++int reftable_writer_add_log(struct reftable_writer *w,
++ struct reftable_log_record *log);
++
++/*
++ Convenience function to add multiple reftable_log_records; the function sorts
++ the records before adding them, reordering records array passed in.
++*/
++int reftable_writer_add_logs(struct reftable_writer *w,
++ struct reftable_log_record *logs, int n);
++
++/* reftable_writer_close finalizes the reftable. The writer is retained so
++ * statistics can be inspected. */
++int reftable_writer_close(struct reftable_writer *w);
++
++/* writer_stats returns the statistics on the reftable being written.
++
++ This struct becomes invalid when the writer is freed.
++ */
++const struct reftable_stats *writer_stats(struct reftable_writer *w);
++
++/* reftable_writer_free deallocates memory for the writer */
++void reftable_writer_free(struct reftable_writer *w);
++
++#endif
## reftable/writer.c (new) ##
@@
@@ reftable/writer.c (new)
+#include "block.h"
+#include "constants.h"
+#include "record.h"
-+#include "reftable.h"
+#include "tree.h"
++#include "reftable-error.h"
+
+/* finishes a block, and writes it to storage */
+static int writer_flush_block(struct reftable_writer *w);
@@ reftable/writer.c (new)
+ w->block_writer->restart_interval = w->opts.restart_interval;
+}
+
++static struct strbuf reftable_empty_strbuf = STRBUF_INIT;
++
+struct reftable_writer *
+reftable_new_writer(int (*writer_func)(void *, const void *, size_t),
+ void *writer_arg, struct reftable_write_options *opts)
@@ reftable/writer.c (new)
+ int err = 0;
+ int i = 0;
+ QSORT(logs, n, reftable_log_record_compare_key);
++
+ for (i = 0; err == 0 && i < n; i++) {
+ err = reftable_writer_add_log(w, &logs[i]);
+ }
@@ reftable/writer.c (new)
+
+done:
+ /* free up memory. */
-+ block_writer_clear(&w->block_writer_data);
++ block_writer_release(&w->block_writer_data);
+ writer_clear_index(w);
+ strbuf_release(&w->last_key);
+ return err;
@@ reftable/writer.h (new)
+
+#include "basics.h"
+#include "block.h"
-+#include "reftable.h"
-+#include "strbuf.h"
+#include "tree.h"
++#include "reftable-writer.h"
+
+struct reftable_writer {
+ int (*write)(void *, const void *, size_t);
10: c196de7f06 ! 11: 9aa2caade8 reftable: read reftable files
@@ Metadata
## Commit message ##
reftable: read reftable files
+ This supports reading a single reftable file.
+
+ The commit introduces an abstract iterator type, which captures the usecases
+ both of reading individual refs, and iterating over a segment of the ref
+ namespace.
+
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
## Makefile ##
-@@ Makefile: REFTABLE_OBJS += reftable/block.o
+@@ Makefile: REFTABLE_OBJS += reftable/basics.o
+ REFTABLE_OBJS += reftable/error.o
+ REFTABLE_OBJS += reftable/block.o
REFTABLE_OBJS += reftable/blocksource.o
- REFTABLE_OBJS += reftable/publicbasics.o
- REFTABLE_OBJS += reftable/compat.o
+REFTABLE_OBJS += reftable/iter.o
+ REFTABLE_OBJS += reftable/publicbasics.o
+REFTABLE_OBJS += reftable/reader.o
REFTABLE_OBJS += reftable/record.o
+REFTABLE_OBJS += reftable/reftable.o
- REFTABLE_OBJS += reftable/strbuf.o
REFTABLE_OBJS += reftable/tree.o
REFTABLE_OBJS += reftable/writer.o
+ REFTABLE_OBJS += reftable/zlib-compat.o
## reftable/iter.c (new) ##
@@
@@ reftable/iter.c (new)
+#include "block.h"
+#include "constants.h"
+#include "reader.h"
-+#include "reftable.h"
++#include "reftable-error.h"
+
+int iterator_is_null(struct reftable_iterator *it)
+{
@@ reftable/iter.c (new)
+int reftable_iterator_next_ref(struct reftable_iterator *it,
+ struct reftable_ref_record *ref)
+{
-+ struct reftable_record rec = { 0 };
++ struct reftable_record rec = { NULL };
+ reftable_record_from_ref(&rec, ref);
+ return iterator_next(it, &rec);
+}
@@ reftable/iter.c (new)
+int reftable_iterator_next_log(struct reftable_iterator *it,
+ struct reftable_log_record *log)
+{
-+ struct reftable_record rec = { 0 };
++ struct reftable_record rec = { NULL };
+ reftable_record_from_log(&rec, log);
+ return iterator_next(it, &rec);
+}
@@ reftable/iter.c (new)
+ }
+
+ if (fri->double_check) {
-+ struct reftable_iterator it = { 0 };
++ struct reftable_iterator it = { NULL };
+
+ err = reftable_table_seek_ref(&fri->tab, &it,
+ ref->refname);
@@ reftable/iter.c (new)
+ }
+ }
+
-+ reftable_ref_record_clear(ref);
++ reftable_ref_record_release(ref);
+ return err;
+}
+
@@ reftable/iter.h (new)
+#ifndef ITER_H
+#define ITER_H
+
++#include "system.h"
+#include "block.h"
+#include "record.h"
-+#include "strbuf.h"
++
++#include "reftable-iterator.h"
++#include "reftable-generic.h"
+
+struct reftable_iterator_vtable {
+ int (*next)(void *iter_arg, struct reftable_record *rec);
@@ reftable/reader.c (new)
+#include "constants.h"
+#include "iter.h"
+#include "record.h"
-+#include "reftable.h"
++#include "reftable-error.h"
+#include "tree.h"
+
+uint64_t block_source_size(struct reftable_block_source *source)
@@ reftable/reader.c (new)
+int init_reader(struct reftable_reader *r, struct reftable_block_source *source,
+ const char *name)
+{
-+ struct reftable_block footer = { 0 };
-+ struct reftable_block header = { 0 };
++ struct reftable_block footer = { NULL };
++ struct reftable_block header = { NULL };
+ int err = 0;
+
+ memset(r, 0, sizeof(struct reftable_reader));
@@ reftable/reader.c (new)
+{
+ int32_t guess_block_size = r->block_size ? r->block_size :
+ DEFAULT_BLOCK_SIZE;
-+ struct reftable_block block = { 0 };
++ struct reftable_block block = { NULL };
+ uint8_t block_typ = 0;
+ int err = 0;
+ uint32_t header_off = next_off ? 0 : header_size(r->version);
@@ reftable/reader.c (new)
+ struct reftable_record *rec)
+{
+ struct reftable_index_record want_index = { .last_key = STRBUF_INIT };
-+ struct reftable_record want_index_rec = { 0 };
++ struct reftable_record want_index_rec = { NULL };
+ struct reftable_index_record index_result = { .last_key = STRBUF_INIT };
-+ struct reftable_record index_result_rec = { 0 };
++ struct reftable_record index_result_rec = { NULL };
+ struct table_iter index_iter = TABLE_ITER_INIT;
+ struct table_iter next = TABLE_ITER_INIT;
+ int err = 0;
@@ reftable/reader.c (new)
+done:
+ block_iter_close(&next.bi);
+ table_iter_close(&index_iter);
-+ reftable_record_clear(&want_index_rec);
-+ reftable_record_clear(&index_result_rec);
++ reftable_record_release(&want_index_rec);
++ reftable_record_release(&index_result_rec);
+ return err;
+}
+
@@ reftable/reader.c (new)
+ struct reftable_ref_record ref = {
+ .refname = (char *)name,
+ };
-+ struct reftable_record rec = { 0 };
++ struct reftable_record rec = { NULL };
+ reftable_record_from_ref(&rec, &ref);
+ return reader_seek(r, it, &rec);
+}
@@ reftable/reader.c (new)
+ .refname = (char *)name,
+ .update_index = update_index,
+ };
-+ struct reftable_record rec = { 0 };
++ struct reftable_record rec = { NULL };
+ reftable_record_from_log(&rec, &log);
+ return reader_seek(r, it, &rec);
+}
@@ reftable/reader.c (new)
+ .hash_prefix = oid,
+ .hash_prefix_len = r->object_id_len,
+ };
-+ struct reftable_record want_rec = { 0 };
-+ struct reftable_iterator oit = { 0 };
-+ struct reftable_obj_record got = { 0 };
-+ struct reftable_record got_rec = { 0 };
++ struct reftable_record want_rec = { NULL };
++ struct reftable_iterator oit = { NULL };
++ struct reftable_obj_record got = { NULL };
++ struct reftable_record got_rec = { NULL };
+ int err = 0;
+ struct indexed_table_ref_iter *itr = NULL;
+
@@ reftable/reader.c (new)
+
+done:
+ reftable_iterator_destroy(&oit);
-+ reftable_record_clear(&got_rec);
++ reftable_record_release(&got_rec);
+ return err;
+}
+
@@ reftable/reader.h (new)
+
+#include "block.h"
+#include "record.h"
-+#include "reftable.h"
++#include "reftable-iterator.h"
++#include "reftable-reader.h"
+
+uint64_t block_source_size(struct reftable_block_source *source);
+
@@ reftable/reader.h (new)
+ uint64_t (*max_update_index)(void *tab);
+};
+
-+int reftable_table_seek_record(struct reftable_table *tab,
-+ struct reftable_iterator *it,
-+ struct reftable_record *rec);
-+
+#endif
- ## reftable/reftable.c (new) ##
+ ## reftable/reftable-iterator.h (new) ##
@@
+/*
+Copyright 2020 Google LLC
@@ reftable/reftable.c (new)
+https://developers.google.com/open-source/licenses/bsd
+*/
+
-+#include "reftable.h"
-+#include "record.h"
-+#include "reader.h"
++#ifndef REFTABLE_ITERATOR_H
++#define REFTABLE_ITERATOR_H
+
-+static int reftable_reader_seek_void(void *tab, struct reftable_iterator *it,
-+ struct reftable_record *rec)
-+{
-+ return reader_seek((struct reftable_reader *)tab, it, rec);
-+}
++#include "reftable-record.h"
+
-+static uint32_t reftable_reader_hash_id_void(void *tab)
-+{
-+ return reftable_reader_hash_id((struct reftable_reader *)tab);
-+}
++/* iterator is the generic interface for walking over data stored in a
++ reftable.
++*/
++struct reftable_iterator {
++ struct reftable_iterator_vtable *ops;
++ void *iter_arg;
++};
+
-+static uint64_t reftable_reader_min_update_index_void(void *tab)
-+{
-+ return reftable_reader_min_update_index((struct reftable_reader *)tab);
-+}
++/* reads the next reftable_ref_record. Returns < 0 for error, 0 for OK and > 0:
++ end of iteration.
++*/
++int reftable_iterator_next_ref(struct reftable_iterator *it,
++ struct reftable_ref_record *ref);
+
-+static uint64_t reftable_reader_max_update_index_void(void *tab)
-+{
-+ return reftable_reader_max_update_index((struct reftable_reader *)tab);
-+}
++/* reads the next reftable_log_record. Returns < 0 for error, 0 for OK and > 0:
++ end of iteration.
++*/
++int reftable_iterator_next_log(struct reftable_iterator *it,
++ struct reftable_log_record *log);
+
-+static struct reftable_table_vtable reader_vtable = {
-+ .seek_record = reftable_reader_seek_void,
-+ .hash_id = reftable_reader_hash_id_void,
-+ .min_update_index = reftable_reader_min_update_index_void,
-+ .max_update_index = reftable_reader_max_update_index_void,
-+};
++/* releases resources associated with an iterator. */
++void reftable_iterator_destroy(struct reftable_iterator *it);
+
-+int reftable_table_seek_ref(struct reftable_table *tab,
-+ struct reftable_iterator *it, const char *name)
-+{
-+ struct reftable_ref_record ref = {
-+ .refname = (char *)name,
-+ };
-+ struct reftable_record rec = { 0 };
-+ reftable_record_from_ref(&rec, &ref);
-+ return tab->ops->seek_record(tab->table_arg, it, &rec);
-+}
++#endif
+
+ ## reftable/reftable-reader.h (new) ##
+@@
++/*
++Copyright 2020 Google LLC
+
-+void reftable_table_from_reader(struct reftable_table *tab,
-+ struct reftable_reader *reader)
-+{
-+ assert(tab->ops == NULL);
-+ tab->ops = &reader_vtable;
-+ tab->table_arg = reader;
-+}
++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
++*/
+
-+int reftable_table_read_ref(struct reftable_table *tab, const char *name,
-+ struct reftable_ref_record *ref)
-+{
-+ struct reftable_iterator it = { 0 };
-+ int err = reftable_table_seek_ref(tab, &it, name);
-+ if (err)
-+ goto done;
++#ifndef REFTABLE_READER_H
++#define REFTABLE_READER_H
+
-+ err = reftable_iterator_next_ref(&it, ref);
-+ if (err)
-+ goto done;
++#include "reftable-iterator.h"
++#include "reftable-blocksource.h"
+
-+ if (strcmp(ref->refname, name) ||
-+ reftable_ref_record_is_deletion(ref)) {
-+ reftable_ref_record_clear(ref);
-+ err = 1;
-+ goto done;
-+ }
++/*
++ Reading single tables
+
-+done:
-+ reftable_iterator_destroy(&it);
-+ return err;
-+}
++ The follow routines are for reading single files. For an application-level
++ interface, skip ahead to struct reftable_merged_table and struct
++ reftable_stack.
++*/
+
-+int reftable_table_seek_record(struct reftable_table *tab,
-+ struct reftable_iterator *it,
-+ struct reftable_record *rec)
-+{
-+ return tab->ops->seek_record(tab->table_arg, it, rec);
-+}
++/* The reader struct is a handle to an open reftable file. */
++struct reftable_reader;
+
-+uint64_t reftable_table_max_update_index(struct reftable_table *tab)
-+{
-+ return tab->ops->max_update_index(tab->table_arg);
-+}
++/* reftable_new_reader opens a reftable for reading. If successful, returns 0
++ * code and sets pp. The name is used for creating a stack. Typically, it is the
++ * basename of the file. The block source `src` is owned by the reader, and is
++ * closed on calling reftable_reader_destroy().
++ */
++int reftable_new_reader(struct reftable_reader **pp,
++ struct reftable_block_source *src, const char *name);
++
++/* reftable_reader_seek_ref returns an iterator where 'name' would be inserted
++ in the table. To seek to the start of the table, use name = "".
++
++ example:
++
++ struct reftable_reader *r = NULL;
++ int err = reftable_new_reader(&r, &src, "filename");
++ if (err < 0) { ... }
++ struct reftable_iterator it = {0};
++ err = reftable_reader_seek_ref(r, &it, "refs/heads/master");
++ if (err < 0) { ... }
++ struct reftable_ref_record ref = {0};
++ while (1) {
++ err = reftable_iterator_next_ref(&it, &ref);
++ if (err > 0) {
++ break;
++ }
++ if (err < 0) {
++ ..error handling..
++ }
++ ..found..
++ }
++ reftable_iterator_destroy(&it);
++ reftable_ref_record_release(&ref);
++ */
++int reftable_reader_seek_ref(struct reftable_reader *r,
++ struct reftable_iterator *it, const char *name);
+
-+uint64_t reftable_table_min_update_index(struct reftable_table *tab)
-+{
-+ return tab->ops->min_update_index(tab->table_arg);
-+}
++/* returns the hash ID used in this table. */
++uint32_t reftable_reader_hash_id(struct reftable_reader *r);
+
-+uint32_t reftable_table_hash_id(struct reftable_table *tab)
-+{
-+ return tab->ops->hash_id(tab->table_arg);
-+}
++/* seek to logs for the given name, older than update_index. To seek to the
++ start of the table, use name = "".
++ */
++int reftable_reader_seek_log_at(struct reftable_reader *r,
++ struct reftable_iterator *it, const char *name,
++ uint64_t update_index);
++
++/* seek to newest log entry for given name. */
++int reftable_reader_seek_log(struct reftable_reader *r,
++ struct reftable_iterator *it, const char *name);
++
++/* closes and deallocates a reader. */
++void reftable_reader_free(struct reftable_reader *);
++
++/* return an iterator for the refs pointing to `oid`. */
++int reftable_reader_refs_for(struct reftable_reader *r,
++ struct reftable_iterator *it, uint8_t *oid);
++
++/* return the max_update_index for a table */
++uint64_t reftable_reader_max_update_index(struct reftable_reader *r);
++
++/* return the min_update_index for a table */
++uint64_t reftable_reader_min_update_index(struct reftable_reader *r);
++
++#endif
11: bf6b929b86 ! 12: 581a4200d6 reftable: file level tests
@@ Metadata
Author: Han-Wen Nienhuys <hanwen@google.com>
## Commit message ##
- reftable: file level tests
+ reftable: reftable file level tests
+
+ With support for reading and writing files in place, we can construct files (in
+ memory) and attempt to read them back.
+
+ Because some sections of the format are optional (eg. indices, log entries), we
+ have to exercise this code using multiple sizes of input data
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
## Makefile ##
@@ Makefile: REFTABLE_OBJS += reftable/zlib-compat.o
-
+ REFTABLE_TEST_OBJS += reftable/basics_test.o
REFTABLE_TEST_OBJS += reftable/block_test.o
REFTABLE_TEST_OBJS += reftable/record_test.o
+REFTABLE_TEST_OBJS += reftable/reftable_test.o
- REFTABLE_TEST_OBJS += reftable/strbuf_test.o
REFTABLE_TEST_OBJS += reftable/test_framework.o
REFTABLE_TEST_OBJS += reftable/tree_test.o
+
## reftable/reftable_test.c (new) ##
@@
@@ reftable/reftable_test.c (new)
+https://developers.google.com/open-source/licenses/bsd
+*/
+
-+#include "reftable.h"
-+
+#include "system.h"
+
+#include "basics.h"
@@ reftable/reftable_test.c (new)
+#include "record.h"
+#include "test_framework.h"
+#include "reftable-tests.h"
++#include "reftable-stack.h"
+
+static const int update_index = 5;
+
@@ reftable/reftable_test.c (new)
+ uint8_t in[] = "hello";
+ strbuf_add(&buf, in, sizeof(in));
+ block_source_from_strbuf(&source, &buf);
-+ assert(block_source_size(&source) == 6);
++ EXPECT(block_source_size(&source) == 6);
+ n = block_source_read_block(&source, &out, 0, sizeof(in));
-+ assert(n == sizeof(in));
-+ assert(!memcmp(in, out.data, n));
++ EXPECT(n == sizeof(in));
++ EXPECT(!memcmp(in, out.data, n));
+ reftable_block_done(&out);
+
+ n = block_source_read_block(&source, &out, 1, 2);
-+ assert(n == 2);
-+ assert(!memcmp(out.data, "el", 2));
++ EXPECT(n == 2);
++ EXPECT(!memcmp(out.data, "el", 2));
+
+ reftable_block_done(&out);
+ block_source_close(&source);
@@ reftable/reftable_test.c (new)
+ (*names)[i] = xstrdup(name);
+
+ n = reftable_writer_add_ref(w, &ref);
-+ assert(n == 0);
++ EXPECT(n == 0);
+ }
+
+ for (i = 0; i < N; i++) {
@@ reftable/reftable_test.c (new)
+ log.message = "message";
+
+ n = reftable_writer_add_log(w, &log);
-+ assert(n == 0);
++ EXPECT(n == 0);
+ }
+
+ n = reftable_writer_close(w);
-+ assert(n == 0);
++ EXPECT(n == 0);
+
+ stats = writer_stats(w);
+ for (i = 0; i < stats->ref_stats.blocks; i++) {
@@ reftable/reftable_test.c (new)
+ if (off == 0) {
+ off = header_size((hash_id == SHA256_ID) ? 2 : 1);
+ }
-+ assert(buf->buf[off] == 'r');
++ EXPECT(buf->buf[off] == 'r');
+ }
+
-+ assert(stats->log_stats.blocks > 0);
++ EXPECT(stats->log_stats.blocks > 0);
+ reftable_writer_free(w);
+}
+
@@ reftable/reftable_test.c (new)
+ log.new_hash = hash2;
+ reftable_writer_set_limits(w, update_index, update_index);
+ err = reftable_writer_add_log(w, &log);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ err = reftable_writer_close(w);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ reftable_writer_free(w);
+ strbuf_release(&buf);
+}
@@ reftable/reftable_test.c (new)
+ ref.update_index = i;
+
+ err = reftable_writer_add_ref(w, &ref);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ }
+ for (i = 0; i < N; i++) {
+ uint8_t hash1[SHA1_SIZE], hash2[SHA1_SIZE];
@@ reftable/reftable_test.c (new)
+ log.new_hash = hash2;
+
+ err = reftable_writer_add_log(w, &log);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ }
+
+ n = reftable_writer_close(w);
-+ assert(n == 0);
++ EXPECT(n == 0);
+
+ stats = writer_stats(w);
-+ assert(stats->log_stats.blocks > 0);
++ EXPECT(stats->log_stats.blocks > 0);
+ reftable_writer_free(w);
+ w = NULL;
+
+ block_source_from_strbuf(&source, &buf);
+
+ err = init_reader(&rd, &source, "file.log");
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_reader_seek_ref(&rd, &it, names[N - 1]);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_iterator_next_ref(&it, &ref);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ /* end of iteration. */
+ err = reftable_iterator_next_ref(&it, &ref);
-+ assert(0 < err);
++ EXPECT(0 < err);
+
+ reftable_iterator_destroy(&it);
-+ reftable_ref_record_clear(&ref);
++ reftable_ref_record_release(&ref);
+
+ err = reftable_reader_seek_log(&rd, &it, "");
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ i = 0;
+ while (1) {
@@ reftable/reftable_test.c (new)
+ break;
+ }
+
-+ assert_err(err);
-+ assert_streq(names[i], log.refname);
-+ assert(i == log.update_index);
++ EXPECT_ERR(err);
++ EXPECT_STREQ(names[i], log.refname);
++ EXPECT(i == log.update_index);
+ i++;
-+ reftable_log_record_clear(&log);
++ reftable_log_record_release(&log);
+ }
+
-+ assert(i == N);
++ EXPECT(i == N);
+ reftable_iterator_destroy(&it);
+
+ /* cleanup. */
@@ reftable/reftable_test.c (new)
+ block_source_from_strbuf(&source, &buf);
+
+ err = init_reader(&rd, &source, "file.ref");
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_reader_seek_ref(&rd, &it, "");
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ while (1) {
+ struct reftable_ref_record ref = { NULL };
+ int r = reftable_iterator_next_ref(&it, &ref);
-+ assert(r >= 0);
++ EXPECT(r >= 0);
+ if (r > 0) {
+ break;
+ }
-+ assert(0 == strcmp(names[j], ref.refname));
-+ assert(update_index == ref.update_index);
++ EXPECT(0 == strcmp(names[j], ref.refname));
++ EXPECT(update_index == ref.update_index);
+
+ j++;
-+ reftable_ref_record_clear(&ref);
++ reftable_ref_record_release(&ref);
+ }
-+ assert(j == N);
++ EXPECT(j == N);
+ reftable_iterator_destroy(&it);
+ strbuf_release(&buf);
+ free_names(names);
@@ reftable/reftable_test.c (new)
+ struct strbuf buf = STRBUF_INIT;
+ int N = 1;
+ write_table(&names, &buf, N, 4096, SHA1_ID);
-+ assert(buf.len < 200);
++ EXPECT(buf.len < 200);
+ strbuf_release(&buf);
+ free_names(names);
+}
@@ reftable/reftable_test.c (new)
+ block_source_from_strbuf(&source, &buf);
+
+ err = init_reader(&rd, &source, "file.ref");
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_reader_seek_ref(&rd, &it, names[0]);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_iterator_next_log(&it, &log);
-+ assert(err == REFTABLE_API_ERROR);
++ EXPECT(err == REFTABLE_API_ERROR);
+
+ strbuf_release(&buf);
+ for (i = 0; i < N; i++) {
@@ reftable/reftable_test.c (new)
+ block_source_from_strbuf(&source, &buf);
+
+ err = init_reader(&rd, &source, "file.ref");
-+ assert_err(err);
-+ assert(hash_id == reftable_reader_hash_id(&rd));
++ EXPECT_ERR(err);
++ EXPECT(hash_id == reftable_reader_hash_id(&rd));
+
+ if (!index) {
+ rd.ref_offsets.index_offset = 0;
+ } else {
-+ assert(rd.ref_offsets.index_offset > 0);
++ EXPECT(rd.ref_offsets.index_offset > 0);
+ }
+
+ for (i = 1; i < N; i++) {
+ int err = reftable_reader_seek_ref(&rd, &it, names[i]);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ err = reftable_iterator_next_ref(&it, &ref);
-+ assert_err(err);
-+ assert(0 == strcmp(names[i], ref.refname));
-+ assert(i == ref.value[0]);
++ EXPECT_ERR(err);
++ EXPECT(0 == strcmp(names[i], ref.refname));
++ EXPECT(i == ref.value[0]);
+
-+ reftable_ref_record_clear(&ref);
++ reftable_ref_record_release(&ref);
+ reftable_iterator_destroy(&it);
+ }
+
@@ reftable/reftable_test.c (new)
+ if (err == 0) {
+ struct reftable_ref_record ref = { NULL };
+ int err = reftable_iterator_next_ref(&it, &ref);
-+ assert(err > 0);
++ EXPECT(err > 0);
+ } else {
-+ assert(err > 0);
++ EXPECT(err > 0);
+ }
+
+ strbuf_release(&pastLast);
@@ reftable/reftable_test.c (new)
+ */
+ /* blocks. */
+ n = reftable_writer_add_ref(w, &ref);
-+ assert(n == 0);
++ EXPECT(n == 0);
+
+ if (!memcmp(hash1, want_hash, SHA1_SIZE) ||
+ !memcmp(hash2, want_hash, SHA1_SIZE)) {
@@ reftable/reftable_test.c (new)
+ }
+
+ n = reftable_writer_close(w);
-+ assert(n == 0);
++ EXPECT(n == 0);
+
+ reftable_writer_free(w);
+ w = NULL;
@@ reftable/reftable_test.c (new)
+ block_source_from_strbuf(&source, &buf);
+
+ err = init_reader(&rd, &source, "file.ref");
-+ assert_err(err);
++ EXPECT_ERR(err);
+ if (!indexed) {
+ rd.obj_offsets.is_present = 0;
+ }
+
+ err = reftable_reader_seek_ref(&rd, &it, "");
-+ assert_err(err);
++ EXPECT_ERR(err);
+ reftable_iterator_destroy(&it);
+
+ err = reftable_reader_refs_for(&rd, &it, want_hash);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ j = 0;
+ while (1) {
+ int err = reftable_iterator_next_ref(&it, &ref);
-+ assert(err >= 0);
++ EXPECT(err >= 0);
+ if (err > 0) {
+ break;
+ }
+
-+ assert(j < want_names_len);
-+ assert(0 == strcmp(ref.refname, want_names[j]));
++ EXPECT(j < want_names_len);
++ EXPECT(0 == strcmp(ref.refname, want_names[j]));
+ j++;
-+ reftable_ref_record_clear(&ref);
++ reftable_ref_record_release(&ref);
+ }
-+ assert(j == want_names_len);
++ EXPECT(j == want_names_len);
+
+ strbuf_release(&buf);
+ free_names(want_names);
@@ reftable/reftable_test.c (new)
+ reftable_writer_set_limits(w, 1, 1);
+
+ err = reftable_writer_close(w);
-+ assert(err == REFTABLE_EMPTY_TABLE_ERROR);
++ EXPECT(err == REFTABLE_EMPTY_TABLE_ERROR);
+ reftable_writer_free(w);
+
-+ assert(buf.len == header_size(1) + footer_size(1));
++ EXPECT(buf.len == header_size(1) + footer_size(1));
+
+ block_source_from_strbuf(&source, &buf);
+
+ err = reftable_new_reader(&rd, &source, "filename");
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_reader_seek_ref(rd, &it, "");
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_iterator_next_ref(&it, &rec);
-+ assert(err > 0);
++ EXPECT(err > 0);
+
+ reftable_iterator_destroy(&it);
+ reftable_reader_free(rd);
@@ reftable/reftable_test.c (new)
+
+int reftable_test_main(int argc, const char *argv[])
+{
-+ add_test_case("test_log_write_read", test_log_write_read);
-+ add_test_case("test_table_read_write_seek_linear_sha256",
-+ &test_table_read_write_seek_linear_sha256);
-+ add_test_case("test_log_buffer_size", test_log_buffer_size);
-+ add_test_case("test_table_write_small_table",
-+ &test_table_write_small_table);
-+ add_test_case("test_buffer", &test_buffer);
-+ add_test_case("test_table_read_api", &test_table_read_api);
-+ add_test_case("test_table_read_write_sequential",
-+ &test_table_read_write_sequential);
-+ add_test_case("test_table_read_write_seek_linear",
-+ &test_table_read_write_seek_linear);
-+ add_test_case("test_table_read_write_seek_index",
-+ &test_table_read_write_seek_index);
-+ add_test_case("test_table_read_write_refs_for_no_index",
-+ &test_table_refs_for_no_index);
-+ add_test_case("test_table_read_write_refs_for_obj_index",
-+ &test_table_refs_for_obj_index);
-+ add_test_case("test_table_empty", &test_table_empty);
-+ return test_main(argc, 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();
++ return 0;
+}
## t/helper/test-reftable.c ##
@@ t/helper/test-reftable.c: int cmd__reftable(int argc, const char **argv)
- {
+ basics_test_main(argc, argv);
block_test_main(argc, argv);
record_test_main(argc, argv);
+ reftable_test_main(argc, argv);
- strbuf_test_main(argc, argv);
tree_test_main(argc, argv);
return 0;
+ }
12: 4e38db7f48 ! 13: a26fb180ad reftable: rest of library
@@ Metadata
## Commit message ##
reftable: rest of library
- This will be further split up once preceding commits have passed review.
-
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
## Makefile ##
-@@ Makefile: XDIFF_OBJS += xdiff/xutils.o
- REFTABLE_OBJS += reftable/basics.o
+@@ Makefile: REFTABLE_OBJS += reftable/error.o
REFTABLE_OBJS += reftable/block.o
REFTABLE_OBJS += reftable/blocksource.o
--REFTABLE_OBJS += reftable/publicbasics.o
- REFTABLE_OBJS += reftable/compat.o
REFTABLE_OBJS += reftable/iter.o
+REFTABLE_OBJS += reftable/merged.o
+REFTABLE_OBJS += reftable/pq.o
-+REFTABLE_OBJS += reftable/publicbasics.o
+ REFTABLE_OBJS += reftable/publicbasics.o
REFTABLE_OBJS += reftable/reader.o
REFTABLE_OBJS += reftable/record.o
+REFTABLE_OBJS += reftable/refname.o
REFTABLE_OBJS += reftable/reftable.o
+REFTABLE_OBJS += reftable/stack.o
- REFTABLE_OBJS += reftable/strbuf.o
REFTABLE_OBJS += reftable/tree.o
REFTABLE_OBJS += reftable/writer.o
-@@ Makefile: REFTABLE_OBJS += reftable/zlib-compat.o
-
- REFTABLE_TEST_OBJS += reftable/block_test.o
- REFTABLE_TEST_OBJS += reftable/record_test.o
-+REFTABLE_TEST_OBJS += reftable/refname_test.o
- REFTABLE_TEST_OBJS += reftable/reftable_test.o
-+REFTABLE_TEST_OBJS += reftable/stack_test.o
- REFTABLE_TEST_OBJS += reftable/strbuf_test.o
- REFTABLE_TEST_OBJS += reftable/test_framework.o
- REFTABLE_TEST_OBJS += reftable/tree_test.o
+ REFTABLE_OBJS += reftable/zlib-compat.o
## reftable/VERSION (new) ##
@@
-+7134eb9f8171a9759800f4187f9e6dde997335e7 C: NULL iso 0 for init
++b8ec0f74c74cb6752eb2033ad8e755a9c19aad15 C: add missing header
## reftable/dump.c (new) ##
@@
@@ reftable/dump.c (new)
+
+static int dump_table(const char *tablename)
+{
-+ struct reftable_block_source src = { NULL };
++ struct reftable_block_source src = { 0 };
+ int err = reftable_block_source_from_file(&src, tablename);
-+ struct reftable_iterator it = { NULL };
-+ struct reftable_ref_record ref = { NULL };
-+ struct reftable_log_record log = { NULL };
++ struct reftable_iterator it = { 0 };
++ struct reftable_ref_record ref = { 0 };
++ struct reftable_log_record log = { 0 };
+ struct reftable_reader *r = NULL;
+
+ if (err < 0)
@@ reftable/dump.c (new)
+{
+ struct reftable_stack *stack = NULL;
+ struct reftable_write_options cfg = {};
-+ struct reftable_iterator it = { NULL };
-+ struct reftable_ref_record ref = { NULL };
-+ struct reftable_log_record log = { NULL };
++ struct reftable_iterator it = { 0 };
++ struct reftable_ref_record ref = { 0 };
++ struct reftable_log_record log = { 0 };
+ struct reftable_merged_table *merged = NULL;
+
+ int err = reftable_new_stack(&stack, stackdir, cfg);
@@ reftable/merged.c (new)
+#include "pq.h"
+#include "reader.h"
+#include "record.h"
-+#include "reftable.h"
++#include "reftable-merged.h"
++#include "reftable-error.h"
+#include "system.h"
+
+static int merged_iter_init(struct merged_iter *mi)
@@ reftable/merged.c (new)
+{
+ struct merged_iter *mi = (struct merged_iter *)p;
+ int i = 0;
-+ merged_iter_pqueue_clear(&mi->pq);
++ merged_iter_pqueue_release(&mi->pq);
+ for (i = 0; i < mi->stack_len; i++) {
+ reftable_iterator_destroy(&mi->stack[i]);
+ }
@@ reftable/merged.c (new)
+}
+
+/* clears the list of subtable, without affecting the readers themselves. */
-+void merged_table_clear(struct reftable_merged_table *mt)
++void merged_table_release(struct reftable_merged_table *mt)
+{
+ FREE_AND_NULL(mt->stack);
+ mt->stack_len = 0;
@@ reftable/merged.c (new)
+ if (mt == NULL) {
+ return;
+ }
-+ merged_table_clear(mt);
++ merged_table_release(mt);
+ reftable_free(mt);
+}
+
@@ reftable/merged.c (new)
+ return mt->min;
+}
+
++static int reftable_table_seek_record(struct reftable_table *tab,
++ struct reftable_iterator *it,
++ struct reftable_record *rec)
++{
++ return tab->ops->seek_record(tab->table_arg, it, rec);
++}
++
+static int merged_table_seek_record(struct reftable_merged_table *mt,
+ struct reftable_iterator *it,
+ struct reftable_record *rec)
@@ reftable/merged.h (new)
+#define MERGED_H
+
+#include "pq.h"
-+#include "reftable.h"
+
+struct reftable_merged_table {
+ struct reftable_table *stack;
@@ reftable/merged.h (new)
+ struct merged_iter_pqueue pq;
+};
+
-+void merged_table_clear(struct reftable_merged_table *mt);
++void merged_table_release(struct reftable_merged_table *mt);
+
+#endif
@@ reftable/merged_test.c (new)
+#include "pq.h"
+#include "reader.h"
+#include "record.h"
-+#include "reftable.h"
+#include "test_framework.h"
++#include "reftable-merged.h"
+#include "reftable-tests.h"
++#include "reftable-generic.h"
++#include "reftable-stack.h"
+
+static void test_pq(void)
+{
@@ reftable/merged_test.c (new)
+ reftable_free(names[i]);
+ }
+
-+ merged_iter_pqueue_clear(&pq);
++ merged_iter_pqueue_release(&pq);
+}
+
+static void write_test_table(struct strbuf *buf,
@@ reftable/merged_test.c (new)
+ }
+
+ err = reftable_writer_close(w);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ reftable_writer_free(w);
+}
@@ reftable/merged_test.c (new)
+
+ err = reftable_new_reader(&(*readers)[i], &(*source)[i],
+ "name");
-+ assert_err(err);
++ EXPECT_ERR(err);
+ reftable_table_from_reader(&tabs[i], (*readers)[i]);
+ }
+
+ err = reftable_new_merged_table(&mt, tabs, n, SHA1_ID);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ return mt;
+}
+
@@ reftable/merged_test.c (new)
+ struct reftable_ref_record ref = { NULL };
+ struct reftable_iterator it = { NULL };
+ int err = reftable_merged_table_seek_ref(mt, &it, "a");
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_iterator_next_ref(&it, &ref);
-+ assert_err(err);
-+ assert(ref.update_index == 2);
-+ reftable_ref_record_clear(&ref);
++ EXPECT_ERR(err);
++ EXPECT(ref.update_index == 2);
++ reftable_ref_record_release(&ref);
+ reftable_iterator_destroy(&it);
+ readers_destroy(readers, 2);
+ reftable_merged_table_free(mt);
@@ reftable/merged_test.c (new)
+ size_t cap = 0;
+ int i = 0;
+
-+ assert_err(err);
++ EXPECT_ERR(err);
+ while (len < 100) { /* cap loops/recursion. */
+ struct reftable_ref_record ref = { NULL };
+ int err = reftable_iterator_next_ref(&it, &ref);
@@ reftable/merged_test.c (new)
+ assert(reftable_ref_record_equal(&want[i], &out[i], SHA1_SIZE));
+ }
+ for (i = 0; i < len; i++) {
-+ reftable_ref_record_clear(&out[i]);
++ reftable_ref_record_release(&out[i]);
+ }
+ reftable_free(out);
+
@@ reftable/merged_test.c (new)
+ reftable_writer_set_limits(w, 1, 1);
+
+ err = reftable_writer_add_ref(w, &rec);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_writer_close(w);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ reftable_writer_free(w);
+
+ block_source_from_strbuf(&source, &buf);
+
+ err = reftable_new_reader(&rd, &source, "filename");
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ hash_id = reftable_reader_hash_id(rd);
+ assert(hash_id == SHA1_ID);
+
+ reftable_table_from_reader(&tab[0], rd);
+ err = reftable_new_merged_table(&merged, tab, 1, SHA1_ID);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ reftable_reader_free(rd);
+ reftable_merged_table_free(merged);
@@ reftable/merged_test.c (new)
+
+int merged_test_main(int argc, const char *argv[])
+{
-+ add_test_case("test_merged_between", &test_merged_between);
-+ add_test_case("test_pq", &test_pq);
-+ add_test_case("test_merged", &test_merged);
-+ add_test_case("test_default_write_opts", &test_default_write_opts);
-+ return test_main(argc, argv);
++ test_merged_between();
++ test_pq();
++ test_merged();
++ test_default_write_opts();
++ return 0;
+}
## reftable/pq.c (new) ##
@@ reftable/pq.c (new)
+
+#include "pq.h"
+
-+#include "reftable.h"
++#include "reftable-record.h"
+#include "system.h"
+#include "basics.h"
+
@@ reftable/pq.c (new)
+ }
+}
+
-+void merged_iter_pqueue_clear(struct merged_iter_pqueue *pq)
++void merged_iter_pqueue_release(struct merged_iter_pqueue *pq)
+{
+ int i = 0;
+ for (i = 0; i < pq->len; i++) {
@@ reftable/pq.h (new)
+void merged_iter_pqueue_check(struct merged_iter_pqueue pq);
+struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq);
+void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, struct pq_entry e);
-+void merged_iter_pqueue_clear(struct merged_iter_pqueue *pq);
++void merged_iter_pqueue_release(struct merged_iter_pqueue *pq);
+
+#endif
@@ reftable/refname.c (new)
+*/
+
+#include "system.h"
-+#include "reftable.h"
++#include "reftable-error.h"
+#include "basics.h"
+#include "refname.h"
-+#include "strbuf.h"
++#include "reftable-iterator.h"
+
+struct find_arg {
+ char **names;
@@ reftable/refname.c (new)
+ }
+
+ err = reftable_table_read_ref(&mod->tab, name, &ref);
-+ reftable_ref_record_clear(&ref);
++ reftable_ref_record_release(&ref);
+ return err;
+}
+
-+static void modification_clear(struct modification *mod)
++static void modification_release(struct modification *mod)
+{
+ /* don't delete the strings themselves; they're owned by ref records.
+ */
@@ reftable/refname.c (new)
+ }
+
+done:
-+ reftable_ref_record_clear(&ref);
++ reftable_ref_record_release(&ref);
+ reftable_iterator_destroy(&it);
+ return err;
+}
@@ reftable/refname.c (new)
+ }
+
+ err = modification_validate(&mod);
-+ modification_clear(&mod);
++ modification_release(&mod);
+ return err;
+}
+
@@ reftable/refname.h (new)
+#ifndef REFNAME_H
+#define REFNAME_H
+
-+#include "reftable.h"
++#include "reftable-record.h"
++#include "reftable-generic.h"
+
+struct modification {
+ struct reftable_table tab;
@@ reftable/refname_test.c (new)
+https://developers.google.com/open-source/licenses/bsd
+*/
+
-+#include "reftable.h"
-+
+#include "basics.h"
+#include "block.h"
+#include "blocksource.h"
@@ reftable/refname_test.c (new)
+#include "reader.h"
+#include "record.h"
+#include "refname.h"
++#include "reftable-error.h"
++#include "reftable-writer.h"
+#include "system.h"
+
+#include "test_framework.h"
@@ reftable/refname_test.c (new)
+ reftable_writer_set_limits(w, 1, 1);
+
+ err = reftable_writer_add_ref(w, &rec);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_writer_close(w);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ reftable_writer_free(w);
+
+ block_source_from_strbuf(&source, &buf);
+ err = reftable_new_reader(&rd, &source, "filename");
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ reftable_table_from_reader(&tab, rd);
+
@@ reftable/refname_test.c (new)
+ }
+
+ err = modification_validate(&mod);
-+ assert(err == cases[i].error_code);
++ EXPECT(err == cases[i].error_code);
+ }
+
+ reftable_reader_free(rd);
@@ reftable/refname_test.c (new)
+
+int refname_test_main(int argc, const char *argv[])
+{
-+ add_test_case("test_conflict", &test_conflict);
-+ return test_main(argc, argv);
++ test_conflict();
++ return 0;
+}
- ## reftable/reftable.c ##
-@@ reftable/reftable.c: int reftable_table_seek_ref(struct reftable_table *tab,
- struct reftable_ref_record ref = {
- .refname = (char *)name,
- };
-- struct reftable_record rec = { 0 };
+ ## reftable/reftable-generic.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 REFTABLE_GENERIC_H
++#define REFTABLE_GENERIC_H
++
++#include "reftable-iterator.h"
++#include "reftable-reader.h"
++#include "reftable-merged.h"
++
++/*
++ Provides a unified API for reading tables, either merged tables, or single
++ readers.
++*/
++struct reftable_table {
++ struct reftable_table_vtable *ops;
++ void *table_arg;
++};
++
++int reftable_table_seek_ref(struct reftable_table *tab,
++ struct reftable_iterator *it, const char *name);
++
++void reftable_table_from_reader(struct reftable_table *tab,
++ struct reftable_reader *reader);
++
++/* returns the hash ID from a generic reftable_table */
++uint32_t reftable_table_hash_id(struct reftable_table *tab);
++
++/* create a generic table from reftable_merged_table */
++void reftable_table_from_merged_table(struct reftable_table *tab,
++ struct reftable_merged_table *table);
++
++/* returns the max update_index covered by this table. */
++uint64_t reftable_table_max_update_index(struct reftable_table *tab);
++
++/* returns the min update_index covered by this table. */
++uint64_t reftable_table_min_update_index(struct reftable_table *tab);
++
++/* convenience function to read a single ref. Returns < 0 for error, 0
++ for success, and 1 if ref not found. */
++int reftable_table_read_ref(struct reftable_table *tab, const char *name,
++ struct reftable_ref_record *ref);
++
++#endif
+
+ ## reftable/reftable-merged.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 REFTABLE_MERGED_H
++#define REFTABLE_MERGED_H
++
++#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.
++*/
++
++/* A merged table is implements seeking/iterating over a stack of tables. */
++struct reftable_merged_table;
++
++/* A generic reftable; see below. */
++struct reftable_table;
++
++/* reftable_new_merged_table creates a new merged table. It takes ownership of
++ the stack array.
++*/
++int reftable_new_merged_table(struct reftable_merged_table **dest,
++ struct reftable_table *stack, int n,
++ uint32_t hash_id);
++
++/* returns an iterator positioned just before 'name' */
++int reftable_merged_table_seek_ref(struct reftable_merged_table *mt,
++ struct reftable_iterator *it,
++ const char *name);
++
++/* returns an iterator for log entry, at given update_index */
++int reftable_merged_table_seek_log_at(struct reftable_merged_table *mt,
++ struct reftable_iterator *it,
++ const char *name, uint64_t update_index);
++
++/* like reftable_merged_table_seek_log_at but look for the newest entry. */
++int reftable_merged_table_seek_log(struct reftable_merged_table *mt,
++ struct reftable_iterator *it,
++ const char *name);
++
++/* returns the max update_index covered by this merged table. */
++uint64_t
++reftable_merged_table_max_update_index(struct reftable_merged_table *mt);
++
++/* returns the min update_index covered by this merged table. */
++uint64_t
++reftable_merged_table_min_update_index(struct reftable_merged_table *mt);
++
++/* releases memory for the merged_table */
++void reftable_merged_table_free(struct reftable_merged_table *m);
++
++/* return the hash ID of the merged table. */
++uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *m);
++
++#endif
+
+ ## reftable/reftable-stack.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 REFTABLE_STACK_H
++#define REFTABLE_STACK_H
++
++#include "reftable-writer.h"
++
++/*
++ 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.
++
++ The reftable_stack automatically compacts files on disk to ensure good
++ amortized performance.
++*/
++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.
++*/
++int reftable_new_stack(struct reftable_stack **dest, const char *dir,
++ struct reftable_write_options config);
++
++/* returns the update_index at which a next table should be written. */
++uint64_t reftable_stack_next_update_index(struct reftable_stack *st);
++
++/* holds a transaction to add tables at the top of a stack. */
++struct reftable_addition;
++
++/*
++ 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);
++
++/* Adds a reftable to transaction. */
++int reftable_addition_add(struct reftable_addition *add,
++ int (*write_table)(struct reftable_writer *wr,
++ void *arg),
++ void *arg);
++
++/* Commits the transaction, releasing the lock. */
++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. */
++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. */
++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.
++*/
++struct reftable_merged_table *
++reftable_stack_merged_table(struct reftable_stack *st);
++
++/* frees all resources associated with the stack. */
++void reftable_stack_destroy(struct reftable_stack *st);
++
++/* Reloads the stack if necessary. This is very cheap to run if the stack was up
++ * to date */
++int reftable_stack_reload(struct reftable_stack *st);
++
++/* Policy for expiring reflog entries. */
++struct reftable_log_expiry_config {
++ /* Drop entries older than this timestamp */
++ uint64_t time;
++
++ /* Drop older entries */
++ uint64_t min_update_index;
++};
++
++/* compacts all reftables into a giant table. Expire reflog entries if config is
++ * non-NULL */
++int reftable_stack_compact_all(struct reftable_stack *st,
++ struct reftable_log_expiry_config *config);
++
++/* 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. */
++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. */
++int reftable_stack_read_log(struct reftable_stack *st, const char *refname,
++ struct reftable_log_record *log);
++
++/* statistics on past compactions. */
++struct reftable_compaction_stats {
++ uint64_t bytes; /* total number of bytes written */
++ uint64_t entries_written; /* total number of entries written, including
++ failures. */
++ int attempts; /* how often we tried to compact */
++ int failures; /* failures happen on concurrent updates */
++};
++
++/* return statistics for compaction up till now. */
++struct reftable_compaction_stats *
++reftable_stack_compaction_stats(struct reftable_stack *st);
++
++#endif
+
+ ## reftable/reftable.c (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
++*/
++
++#include "record.h"
++#include "reader.h"
++#include "reftable-iterator.h"
++#include "reftable-generic.h"
++
++static int reftable_reader_seek_void(void *tab, struct reftable_iterator *it,
++ struct reftable_record *rec)
++{
++ return reader_seek((struct reftable_reader *)tab, it, rec);
++}
++
++static uint32_t reftable_reader_hash_id_void(void *tab)
++{
++ return reftable_reader_hash_id((struct reftable_reader *)tab);
++}
++
++static uint64_t reftable_reader_min_update_index_void(void *tab)
++{
++ return reftable_reader_min_update_index((struct reftable_reader *)tab);
++}
++
++static uint64_t reftable_reader_max_update_index_void(void *tab)
++{
++ return reftable_reader_max_update_index((struct reftable_reader *)tab);
++}
++
++static struct reftable_table_vtable reader_vtable = {
++ .seek_record = reftable_reader_seek_void,
++ .hash_id = reftable_reader_hash_id_void,
++ .min_update_index = reftable_reader_min_update_index_void,
++ .max_update_index = reftable_reader_max_update_index_void,
++};
++
++int reftable_table_seek_ref(struct reftable_table *tab,
++ struct reftable_iterator *it, const char *name)
++{
++ struct reftable_ref_record ref = {
++ .refname = (char *)name,
++ };
+ struct reftable_record rec = { NULL };
- reftable_record_from_ref(&rec, &ref);
- return tab->ops->seek_record(tab->table_arg, it, &rec);
- }
-@@ reftable/reftable.c: void reftable_table_from_reader(struct reftable_table *tab,
- int reftable_table_read_ref(struct reftable_table *tab, const char *name,
- struct reftable_ref_record *ref)
- {
-- struct reftable_iterator it = { 0 };
++ reftable_record_from_ref(&rec, &ref);
++ return tab->ops->seek_record(tab->table_arg, it, &rec);
++}
++
++void reftable_table_from_reader(struct reftable_table *tab,
++ struct reftable_reader *reader)
++{
++ assert(tab->ops == NULL);
++ tab->ops = &reader_vtable;
++ tab->table_arg = reader;
++}
++
++int reftable_table_read_ref(struct reftable_table *tab, const char *name,
++ struct reftable_ref_record *ref)
++{
+ struct reftable_iterator it = { NULL };
- int err = reftable_table_seek_ref(tab, &it, name);
- if (err)
- goto done;
++ int err = reftable_table_seek_ref(tab, &it, name);
++ if (err)
++ goto done;
++
++ err = reftable_iterator_next_ref(&it, ref);
++ if (err)
++ goto done;
++
++ if (strcmp(ref->refname, name) ||
++ reftable_ref_record_is_deletion(ref)) {
++ reftable_ref_record_release(ref);
++ err = 1;
++ goto done;
++ }
++
++done:
++ reftable_iterator_destroy(&it);
++ return err;
++}
++
++uint64_t reftable_table_max_update_index(struct reftable_table *tab)
++{
++ return tab->ops->max_update_index(tab->table_arg);
++}
++
++uint64_t reftable_table_min_update_index(struct reftable_table *tab)
++{
++ return tab->ops->min_update_index(tab->table_arg);
++}
++
++uint32_t reftable_table_hash_id(struct reftable_table *tab)
++{
++ return tab->ops->hash_id(tab->table_arg);
++}
## reftable/stack.c (new) ##
@@
@@ reftable/stack.c (new)
+#include "merged.h"
+#include "reader.h"
+#include "refname.h"
-+#include "reftable.h"
++#include "reftable-error.h"
++#include "reftable-record.h"
+#include "writer.h"
+
+static int stack_try_add(struct reftable_stack *st,
@@ reftable/stack.c (new)
+static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st,
+ int reuse_open);
+
++static int reftable_fd_write(void *arg, const void *data, size_t sz)
++{
++ int *fdp = (int *)arg;
++ return write(*fdp, data, sz);
++}
++
+int reftable_new_stack(struct reftable_stack **dest, const char *dir,
+ struct reftable_write_options config)
+{
@@ reftable/stack.c (new)
+ new_tables = NULL;
+ st->readers_len = new_readers_len;
+ if (st->merged != NULL) {
-+ merged_table_clear(st->merged);
++ merged_table_release(st->merged);
+ reftable_merged_table_free(st->merged);
+ }
+ if (st->readers != NULL) {
@@ reftable/stack.c (new)
+done:
+ reftable_iterator_destroy(&it);
+ if (mt != NULL) {
-+ merged_table_clear(mt);
++ merged_table_release(mt);
+ reftable_merged_table_free(mt);
+ }
-+ reftable_ref_record_clear(&ref);
-+ reftable_log_record_clear(&log);
++ reftable_ref_record_release(&ref);
++ reftable_log_record_release(&log);
+ st->stats.entries_written += entries;
+ return err;
+}
@@ reftable/stack.c (new)
+
+done:
+ if (err) {
-+ reftable_log_record_clear(log);
++ reftable_log_record_release(log);
+ }
+ reftable_iterator_destroy(&it);
+ return err;
@@ reftable/stack.c (new)
+
+done:
+ for (i = 0; i < len; i++) {
-+ reftable_ref_record_clear(&refs[i]);
++ reftable_ref_record_release(&refs[i]);
+ }
+
+ free(refs);
@@ reftable/stack.h (new)
+#ifndef STACK_H
+#define STACK_H
+
-+#include "reftable.h"
+#include "system.h"
++#include "reftable-writer.h"
++#include "reftable-stack.h"
+
+struct reftable_stack {
+ char *list_file;
@@ reftable/stack_test.c (new)
+#include "basics.h"
+#include "constants.h"
+#include "record.h"
-+#include "reftable.h"
+#include "test_framework.h"
+#include "reftable-tests.h"
+
+#include <sys/types.h>
+#include <dirent.h>
+
++static void clear_dir(const char *dirname)
++{
++ struct strbuf path = STRBUF_INIT;
++ strbuf_addstr(&path, dirname);
++ remove_dir_recursively(&path, 0);
++ strbuf_release(&path);
++}
++
+static void test_read_file(void)
+{
+ char fn[256] = "/tmp/stack.test_read_file.XXXXXX";
@@ reftable/stack_test.c (new)
+ char *want[] = { "line1", "line2", "line3" };
+ int i = 0;
+
-+ assert(fd > 0);
++ EXPECT(fd > 0);
+ n = write(fd, out, strlen(out));
-+ assert(n == strlen(out));
++ EXPECT(n == strlen(out));
+ err = close(fd);
-+ assert(err >= 0);
++ EXPECT(err >= 0);
+
+ err = read_lines(fn, &names);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ for (i = 0; names[i] != NULL; i++) {
-+ assert(0 == strcmp(want[i], names[i]));
++ EXPECT(0 == strcmp(want[i], names[i]));
+ }
+ free_names(names);
+ remove(fn);
@@ reftable/stack_test.c (new)
+ char **names = NULL;
+ parse_names(buf, strlen(buf), &names);
+
-+ assert(NULL != names[0]);
-+ assert(0 == strcmp(names[0], "line"));
-+ assert(NULL == names[1]);
++ EXPECT(NULL != names[0]);
++ EXPECT(0 == strcmp(names[0], "line"));
++ EXPECT(NULL == names[1]);
+ free_names(names);
+}
+
@@ reftable/stack_test.c (new)
+ char *b[] = { "a", "b", "d", NULL };
+ char *c[] = { "a", "b", NULL };
+
-+ assert(names_equal(a, a));
-+ assert(!names_equal(a, b));
-+ assert(!names_equal(a, c));
++ EXPECT(names_equal(a, a));
++ EXPECT(!names_equal(a, b));
++ EXPECT(!names_equal(a, c));
+}
+
+static int write_test_ref(struct reftable_writer *wr, void *arg)
@@ reftable/stack_test.c (new)
+ };
+ struct reftable_ref_record dest = { NULL };
+
-+ assert(mkdtemp(dir));
++ EXPECT(mkdtemp(dir));
+
+ err = reftable_new_stack(&st, dir, cfg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_add(st, &write_test_ref, &ref);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_read_ref(st, ref.refname, &dest);
-+ assert_err(err);
-+ assert(0 == strcmp("master", dest.target));
++ EXPECT_ERR(err);
++ EXPECT(0 == strcmp("master", dest.target));
+
-+ reftable_ref_record_clear(&dest);
++ reftable_ref_record_release(&dest);
+ reftable_stack_destroy(st);
-+ reftable_clear_dir(dir);
++ clear_dir(dir);
+}
+
+static void test_reftable_stack_uptodate(void)
@@ reftable/stack_test.c (new)
+ .target = "master",
+ };
+
-+ assert(mkdtemp(dir));
++ EXPECT(mkdtemp(dir));
+
+ err = reftable_new_stack(&st1, dir, cfg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_new_stack(&st2, dir, cfg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_add(st1, &write_test_ref, &ref1);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_add(st2, &write_test_ref, &ref2);
-+ assert(err == REFTABLE_LOCK_ERROR);
++ EXPECT(err == REFTABLE_LOCK_ERROR);
+
+ err = reftable_stack_reload(st2);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_add(st2, &write_test_ref, &ref2);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ reftable_stack_destroy(st1);
+ reftable_stack_destroy(st2);
-+ reftable_clear_dir(dir);
++ clear_dir(dir);
+}
+
+static void test_reftable_stack_transaction_api(void)
@@ reftable/stack_test.c (new)
+ };
+ struct reftable_ref_record dest = { NULL };
+
-+ assert(mkdtemp(dir));
++ EXPECT(mkdtemp(dir));
+
+ err = reftable_new_stack(&st, dir, cfg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ reftable_addition_destroy(add);
+
+ err = reftable_stack_new_addition(&add, st);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_addition_add(add, &write_test_ref, &ref);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_addition_commit(add);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ reftable_addition_destroy(add);
+
+ err = reftable_stack_read_ref(st, ref.refname, &dest);
-+ assert_err(err);
-+ assert(0 == strcmp("master", dest.target));
++ EXPECT_ERR(err);
++ EXPECT(0 == strcmp("master", dest.target));
+
-+ reftable_ref_record_clear(&dest);
++ reftable_ref_record_release(&dest);
+ reftable_stack_destroy(st);
-+ reftable_clear_dir(dir);
++ clear_dir(dir);
+}
+
+static void test_reftable_stack_validate_refname(void)
@@ reftable/stack_test.c (new)
+ };
+ char *additions[] = { "a", "a/b/c" };
+
-+ assert(mkdtemp(dir));
++ EXPECT(mkdtemp(dir));
+ err = reftable_new_stack(&st, dir, cfg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_add(st, &write_test_ref, &ref);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ for (i = 0; i < ARRAY_SIZE(additions); i++) {
+ struct reftable_ref_record ref = {
@@ reftable/stack_test.c (new)
+ };
+
+ err = reftable_stack_add(st, &write_test_ref, &ref);
-+ assert(err == REFTABLE_NAME_CONFLICT);
++ EXPECT(err == REFTABLE_NAME_CONFLICT);
+ }
+
+ reftable_stack_destroy(st);
-+ reftable_clear_dir(dir);
++ clear_dir(dir);
+}
+
+static int write_error(struct reftable_writer *wr, void *arg)
@@ reftable/stack_test.c (new)
+ .update_index = 1,
+ .target = "master",
+ };
-+ assert(mkdtemp(dir));
++ EXPECT(mkdtemp(dir));
+
+ err = reftable_new_stack(&st, dir, cfg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_add(st, &write_test_ref, &ref1);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_add(st, &write_test_ref, &ref2);
-+ assert(err == REFTABLE_API_ERROR);
++ EXPECT(err == REFTABLE_API_ERROR);
+ reftable_stack_destroy(st);
-+ reftable_clear_dir(dir);
++ clear_dir(dir);
+}
+
+static void test_reftable_stack_lock_failure(void)
@@ reftable/stack_test.c (new)
+ struct reftable_write_options cfg = { 0 };
+ struct reftable_stack *st = NULL;
+ int err, i;
-+ assert(mkdtemp(dir));
++ EXPECT(mkdtemp(dir));
+
+ err = reftable_new_stack(&st, dir, cfg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ for (i = -1; i != REFTABLE_EMPTY_TABLE_ERROR; i--) {
+ err = reftable_stack_add(st, &write_error, &i);
-+ assert(err == i);
++ EXPECT(err == i);
+ }
+
+ reftable_stack_destroy(st);
-+ reftable_clear_dir(dir);
++ clear_dir(dir);
+}
+
+static void test_reftable_stack_add(void)
@@ reftable/stack_test.c (new)
+ struct reftable_log_record logs[2] = { { NULL } };
+ int N = ARRAY_SIZE(refs);
+
-+ assert(mkdtemp(dir));
++ EXPECT(mkdtemp(dir));
+
+ err = reftable_new_stack(&st, dir, cfg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ st->disable_auto_compact = 1;
+
+ for (i = 0; i < N; i++) {
@@ reftable/stack_test.c (new)
+
+ for (i = 0; i < N; i++) {
+ int err = reftable_stack_add(st, &write_test_ref, &refs[i]);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ }
+
+ for (i = 0; i < N; i++) {
@@ reftable/stack_test.c (new)
+ .update_index = reftable_stack_next_update_index(st),
+ };
+ int err = reftable_stack_add(st, &write_test_log, &arg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ }
+
+ err = reftable_stack_compact_all(st, NULL);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ for (i = 0; i < N; i++) {
+ struct reftable_ref_record dest = { NULL };
+
+ int err = reftable_stack_read_ref(st, refs[i].refname, &dest);
-+ assert_err(err);
-+ assert(reftable_ref_record_equal(&dest, refs + i, SHA1_SIZE));
-+ reftable_ref_record_clear(&dest);
++ EXPECT_ERR(err);
++ EXPECT(reftable_ref_record_equal(&dest, refs + i, SHA1_SIZE));
++ reftable_ref_record_release(&dest);
+ }
+
+ for (i = 0; i < N; i++) {
+ struct reftable_log_record dest = { NULL };
+ int err = reftable_stack_read_log(st, refs[i].refname, &dest);
-+ assert_err(err);
-+ assert(reftable_log_record_equal(&dest, logs + i, SHA1_SIZE));
-+ reftable_log_record_clear(&dest);
++ EXPECT_ERR(err);
++ EXPECT(reftable_log_record_equal(&dest, logs + i, SHA1_SIZE));
++ reftable_log_record_release(&dest);
+ }
+
+ /* cleanup */
+ reftable_stack_destroy(st);
+ for (i = 0; i < N; i++) {
-+ reftable_ref_record_clear(&refs[i]);
-+ reftable_log_record_clear(&logs[i]);
++ reftable_ref_record_release(&refs[i]);
++ reftable_log_record_release(&logs[i]);
+ }
-+ reftable_clear_dir(dir);
++ clear_dir(dir);
+}
+
+static void test_reftable_stack_log_normalize(void)
@@ reftable/stack_test.c (new)
+ .update_index = 1,
+ };
+
-+ assert(mkdtemp(dir));
++ EXPECT(mkdtemp(dir));
+ err = reftable_new_stack(&st, dir, cfg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ input.message = "one\ntwo";
+ err = reftable_stack_add(st, &write_test_log, &arg);
-+ assert(err == REFTABLE_API_ERROR);
++ EXPECT(err == REFTABLE_API_ERROR);
+
+ input.message = "one";
+ err = reftable_stack_add(st, &write_test_log, &arg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_read_log(st, input.refname, &dest);
-+ assert_err(err);
-+ assert(0 == strcmp(dest.message, "one\n"));
++ EXPECT_ERR(err);
++ EXPECT(0 == strcmp(dest.message, "one\n"));
+
+ input.message = "two\n";
+ arg.update_index = 2;
+ err = reftable_stack_add(st, &write_test_log, &arg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ err = reftable_stack_read_log(st, input.refname, &dest);
-+ assert_err(err);
-+ assert(0 == strcmp(dest.message, "two\n"));
++ EXPECT_ERR(err);
++ EXPECT(0 == strcmp(dest.message, "two\n"));
+
+ /* cleanup */
+ reftable_stack_destroy(st);
-+ reftable_log_record_clear(&dest);
-+ reftable_clear_dir(dir);
++ reftable_log_record_release(&dest);
++ clear_dir(dir);
+}
+
+static void test_reftable_stack_tombstone(void)
@@ reftable/stack_test.c (new)
+ struct reftable_ref_record dest = { NULL };
+ struct reftable_log_record log_dest = { NULL };
+
-+ assert(mkdtemp(dir));
++ EXPECT(mkdtemp(dir));
+
+ err = reftable_new_stack(&st, dir, cfg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ for (i = 0; i < N; i++) {
+ const char *buf = "branch";
@@ reftable/stack_test.c (new)
+ }
+ for (i = 0; i < N; i++) {
+ int err = reftable_stack_add(st, &write_test_ref, &refs[i]);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ }
+ for (i = 0; i < N; i++) {
+ struct write_log_arg arg = {
@@ reftable/stack_test.c (new)
+ .update_index = reftable_stack_next_update_index(st),
+ };
+ int err = reftable_stack_add(st, &write_test_log, &arg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ }
+
+ err = reftable_stack_read_ref(st, "branch", &dest);
-+ assert(err == 1);
-+ reftable_ref_record_clear(&dest);
++ EXPECT(err == 1);
++ reftable_ref_record_release(&dest);
+
+ err = reftable_stack_read_log(st, "branch", &log_dest);
-+ assert(err == 1);
-+ reftable_log_record_clear(&log_dest);
++ EXPECT(err == 1);
++ reftable_log_record_release(&log_dest);
+
+ err = reftable_stack_compact_all(st, NULL);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_read_ref(st, "branch", &dest);
-+ assert(err == 1);
++ EXPECT(err == 1);
+
+ err = reftable_stack_read_log(st, "branch", &log_dest);
-+ assert(err == 1);
-+ reftable_ref_record_clear(&dest);
-+ reftable_log_record_clear(&log_dest);
++ EXPECT(err == 1);
++ reftable_ref_record_release(&dest);
++ reftable_log_record_release(&log_dest);
+
+ /* cleanup */
+ reftable_stack_destroy(st);
+ for (i = 0; i < N; i++) {
-+ reftable_ref_record_clear(&refs[i]);
-+ reftable_log_record_clear(&logs[i]);
++ reftable_ref_record_release(&refs[i]);
++ reftable_log_record_release(&logs[i]);
+ }
-+ reftable_clear_dir(dir);
++ clear_dir(dir);
+}
+
+static void test_reftable_stack_hash_id(void)
@@ reftable/stack_test.c (new)
+ struct reftable_stack *st_default = NULL;
+ struct reftable_ref_record dest = { NULL };
+
-+ assert(mkdtemp(dir));
++ EXPECT(mkdtemp(dir));
+ err = reftable_new_stack(&st, dir, cfg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_add(st, &write_test_ref, &ref);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ /* can't read it with the wrong hash ID. */
+ err = reftable_new_stack(&st32, dir, cfg32);
-+ assert(err == REFTABLE_FORMAT_ERROR);
++ EXPECT(err == REFTABLE_FORMAT_ERROR);
+
+ /* check that we can read it back with default config too. */
+ err = reftable_new_stack(&st_default, dir, cfg_default);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_read_ref(st_default, "master", &dest);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
-+ assert(!strcmp(dest.target, ref.target));
-+ reftable_ref_record_clear(&dest);
++ EXPECT(!strcmp(dest.target, ref.target));
++ reftable_ref_record_release(&dest);
+ reftable_stack_destroy(st);
+ reftable_stack_destroy(st_default);
-+ reftable_clear_dir(dir);
++ clear_dir(dir);
+}
+
+static void test_log2(void)
+{
-+ assert(1 == fastlog2(3));
-+ assert(2 == fastlog2(4));
-+ assert(2 == fastlog2(5));
++ EXPECT(1 == fastlog2(3));
++ EXPECT(2 == fastlog2(4));
++ EXPECT(2 == fastlog2(5));
+}
+
+static void test_sizes_to_segments(void)
@@ reftable/stack_test.c (new)
+ int seglen = 0;
+ struct segment *segs =
+ sizes_to_segments(&seglen, sizes, ARRAY_SIZE(sizes));
-+ assert(segs[2].log == 3);
-+ assert(segs[2].start == 5);
-+ assert(segs[2].end == 6);
++ EXPECT(segs[2].log == 3);
++ EXPECT(segs[2].start == 5);
++ EXPECT(segs[2].end == 6);
+
-+ assert(segs[1].log == 2);
-+ assert(segs[1].start == 2);
-+ assert(segs[1].end == 5);
++ EXPECT(segs[1].log == 2);
++ EXPECT(segs[1].start == 2);
++ EXPECT(segs[1].end == 5);
+ reftable_free(segs);
+}
+
@@ reftable/stack_test.c (new)
+ int seglen = 0;
+ struct segment *segs =
+ sizes_to_segments(&seglen, sizes, ARRAY_SIZE(sizes));
-+ assert(seglen == 0);
++ EXPECT(seglen == 0);
+ reftable_free(segs);
+}
+
@@ reftable/stack_test.c (new)
+ int seglen = 0;
+ struct segment *segs =
+ sizes_to_segments(&seglen, sizes, ARRAY_SIZE(sizes));
-+ assert(seglen == 1);
-+ assert(segs[0].start == 0);
-+ assert(segs[0].end == 2);
++ EXPECT(seglen == 1);
++ EXPECT(segs[0].start == 0);
++ EXPECT(segs[0].end == 2);
+ reftable_free(segs);
+}
+
@@ reftable/stack_test.c (new)
+ /* .................0 1 2 3 4 5 6 */
+ struct segment min =
+ suggest_compaction_segment(sizes, ARRAY_SIZE(sizes));
-+ assert(min.start == 2);
-+ assert(min.end == 7);
++ EXPECT(min.start == 2);
++ EXPECT(min.end == 7);
+}
+
+static void test_suggest_compaction_segment_nothing(void)
@@ reftable/stack_test.c (new)
+ uint64_t sizes[] = { 64, 32, 16, 8, 4, 2 };
+ struct segment result =
+ suggest_compaction_segment(sizes, ARRAY_SIZE(sizes));
-+ assert(result.start == result.end);
++ EXPECT(result.start == result.end);
+}
+
+static void test_reflog_expire(void)
@@ reftable/stack_test.c (new)
+ };
+ struct reftable_log_record log = { NULL };
+
-+ assert(mkdtemp(dir));
++ EXPECT(mkdtemp(dir));
+
+ err = reftable_new_stack(&st, dir, cfg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ for (i = 1; i <= N; i++) {
+ char buf[256];
@@ reftable/stack_test.c (new)
+ .update_index = reftable_stack_next_update_index(st),
+ };
+ int err = reftable_stack_add(st, &write_test_log, &arg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+ }
+
+ err = reftable_stack_compact_all(st, NULL);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_compact_all(st, &expiry);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_read_log(st, logs[9].refname, &log);
-+ assert(err == 1);
++ EXPECT(err == 1);
+
+ err = reftable_stack_read_log(st, logs[11].refname, &log);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ expiry.min_update_index = 15;
+ err = reftable_stack_compact_all(st, &expiry);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_read_log(st, logs[14].refname, &log);
-+ assert(err == 1);
++ EXPECT(err == 1);
+
+ err = reftable_stack_read_log(st, logs[16].refname, &log);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ /* cleanup */
+ reftable_stack_destroy(st);
+ for (i = 0; i <= N; i++) {
-+ reftable_log_record_clear(&logs[i]);
++ reftable_log_record_release(&logs[i]);
+ }
-+ reftable_clear_dir(dir);
-+ reftable_log_record_clear(&log);
++ clear_dir(dir);
++ reftable_log_record_release(&log);
+}
+
+static int write_nothing(struct reftable_writer *wr, void *arg)
@@ reftable/stack_test.c (new)
+ char dir[256] = "/tmp/stack_test.XXXXXX";
+ struct reftable_stack *st2 = NULL;
+
-+ assert(mkdtemp(dir));
++ EXPECT(mkdtemp(dir));
+
+ err = reftable_new_stack(&st, dir, cfg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_stack_add(st, &write_nothing, NULL);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ err = reftable_new_stack(&st2, dir, cfg);
-+ assert_err(err);
-+ reftable_clear_dir(dir);
++ EXPECT_ERR(err);
++ clear_dir(dir);
+ reftable_stack_destroy(st);
+ reftable_stack_destroy(st2);
+}
@@ reftable/stack_test.c (new)
+ char dir[256] = "/tmp/stack_test.XXXXXX";
+ int err, i;
+ int N = 100;
-+ assert(mkdtemp(dir));
++ EXPECT(mkdtemp(dir));
+
+ err = reftable_new_stack(&st, dir, cfg);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
+ for (i = 0; i < N; i++) {
+ char name[100];
@@ reftable/stack_test.c (new)
+ snprintf(name, sizeof(name), "branch%04d", i);
+
+ err = reftable_stack_add(st, &write_test_ref, &ref);
-+ assert_err(err);
++ EXPECT_ERR(err);
+
-+ assert(i < 3 || st->merged->stack_len < 2 * fastlog2(i));
++ EXPECT(i < 3 || st->merged->stack_len < 2 * fastlog2(i));
+ }
+
-+ assert(reftable_stack_compaction_stats(st)->entries_written <
++ EXPECT(reftable_stack_compaction_stats(st)->entries_written <
+ (uint64_t)(N * fastlog2(N)));
+
+ reftable_stack_destroy(st);
-+ reftable_clear_dir(dir);
++ clear_dir(dir);
+}
+
+int stack_test_main(int argc, const char *argv[])
+{
-+ add_test_case("test_reftable_stack_uptodate",
-+ &test_reftable_stack_uptodate);
-+ add_test_case("test_reftable_stack_transaction_api",
-+ &test_reftable_stack_transaction_api);
-+ add_test_case("test_reftable_stack_hash_id",
-+ &test_reftable_stack_hash_id);
-+ add_test_case("test_sizes_to_segments_all_equal",
-+ &test_sizes_to_segments_all_equal);
-+ add_test_case("test_reftable_stack_auto_compaction",
-+ &test_reftable_stack_auto_compaction);
-+ add_test_case("test_reftable_stack_validate_refname",
-+ &test_reftable_stack_validate_refname);
-+ add_test_case("test_reftable_stack_update_index_check",
-+ &test_reftable_stack_update_index_check);
-+ add_test_case("test_reftable_stack_lock_failure",
-+ &test_reftable_stack_lock_failure);
-+ add_test_case("test_reftable_stack_log_normalize",
-+ &test_reftable_stack_log_normalize);
-+ add_test_case("test_reftable_stack_tombstone",
-+ &test_reftable_stack_tombstone);
-+ add_test_case("test_reftable_stack_add_one",
-+ &test_reftable_stack_add_one);
-+ add_test_case("test_empty_add", test_empty_add);
-+ add_test_case("test_reflog_expire", test_reflog_expire);
-+ add_test_case("test_suggest_compaction_segment",
-+ &test_suggest_compaction_segment);
-+ add_test_case("test_suggest_compaction_segment_nothing",
-+ &test_suggest_compaction_segment_nothing);
-+ add_test_case("test_sizes_to_segments", &test_sizes_to_segments);
-+ add_test_case("test_sizes_to_segments_empty",
-+ &test_sizes_to_segments_empty);
-+ add_test_case("test_log2", &test_log2);
-+ add_test_case("test_parse_names", &test_parse_names);
-+ add_test_case("test_read_file", &test_read_file);
-+ add_test_case("test_names_equal", &test_names_equal);
-+ add_test_case("test_reftable_stack_add", &test_reftable_stack_add);
-+ return test_main(argc, 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();
++ return 0;
+}
- ## reftable/update.sh (new) ##
-@@
-+#!/bin/sh
-+
-+set -eu
-+
-+# Override this to import from somewhere else, say "../reftable".
-+SRC=${SRC:-origin}
-+BRANCH=${BRANCH:-master}
-+
-+((git --git-dir reftable-repo/.git fetch -f ${SRC} ${BRANCH}:import && cd reftable-repo && git checkout -f $(git rev-parse import) ) ||
-+ git clone https://github.com/google/reftable reftable-repo)
-+
-+cp reftable-repo/c/*.[ch] reftable/
-+cp reftable-repo/c/include/*.[ch] reftable/
-+cp reftable-repo/LICENSE reftable/
-+
-+git --git-dir reftable-repo/.git show --no-patch --format=oneline HEAD \
-+ > reftable/VERSION
-+
-+mv reftable/system.h reftable/system.h~
-+sed 's|if REFTABLE_IN_GITCORE|if 1 /* REFTABLE_IN_GITCORE */|' < reftable/system.h~ > reftable/system.h
-+
-+git add reftable/*.[ch] reftable/LICENSE reftable/VERSION
-
## t/helper/test-reftable.c ##
-@@
- int cmd__reftable(int argc, const char **argv)
+@@ t/helper/test-reftable.c: int cmd__reftable(int argc, const char **argv)
{
+ basics_test_main(argc, argv);
block_test_main(argc, argv);
+ merged_test_main(argc, argv);
record_test_main(argc, argv);
+ refname_test_main(argc, argv);
reftable_test_main(argc, argv);
- strbuf_test_main(argc, argv);
+ stack_test_main(argc, argv);
tree_test_main(argc, argv);
return 0;
-: ---------- > 14: a590865a70 Reftable support for git-core
-: ---------- > 15: 57626bfe2d git-prompt: prepare for reftable refs backend
13: c535f838d6 ! 16: 6229da992e reftable: "test-tool dump-reftable" command.
@@ Metadata
Author: Han-Wen Nienhuys <hanwen@google.com>
## Commit message ##
- reftable: "test-tool dump-reftable" command.
+ Add "test-tool dump-reftable" command.
This command dumps individual tables or a stack of of tables.
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
## Makefile ##
-@@ Makefile: REFTABLE_OBJS += reftable/writer.o
- REFTABLE_OBJS += reftable/zlib-compat.o
+@@ Makefile: REFTABLE_OBJS += reftable/zlib-compat.o
+ REFTABLE_TEST_OBJS += reftable/basics_test.o
REFTABLE_TEST_OBJS += reftable/block_test.o
+REFTABLE_TEST_OBJS += reftable/dump.o
-+REFTABLE_TEST_OBJS += reftable/merged_test.o
+ REFTABLE_TEST_OBJS += reftable/merged_test.o
REFTABLE_TEST_OBJS += reftable/record_test.o
REFTABLE_TEST_OBJS += reftable/refname_test.o
- REFTABLE_TEST_OBJS += reftable/reftable_test.o
- ## reftable/iter.c ##
-@@ reftable/iter.c: void reftable_iterator_destroy(struct reftable_iterator *it)
- int reftable_iterator_next_ref(struct reftable_iterator *it,
- struct reftable_ref_record *ref)
- {
-- struct reftable_record rec = { 0 };
-+ struct reftable_record rec = { NULL };
- reftable_record_from_ref(&rec, ref);
- return iterator_next(it, &rec);
- }
-@@ reftable/iter.c: int reftable_iterator_next_ref(struct reftable_iterator *it,
- int reftable_iterator_next_log(struct reftable_iterator *it,
- struct reftable_log_record *log)
- {
-- struct reftable_record rec = { 0 };
-+ struct reftable_record rec = { NULL };
- reftable_record_from_log(&rec, log);
- return iterator_next(it, &rec);
- }
-@@ reftable/iter.c: static int filtering_ref_iterator_next(void *iter_arg,
- }
+ ## reftable/dump.c ##
+@@ reftable/dump.c: license that can be found in the LICENSE file or at
+ #include <unistd.h>
+ #include <string.h>
- if (fri->double_check) {
-- struct reftable_iterator it = { 0 };
-+ struct reftable_iterator it = { NULL };
+-#include "reftable.h"
++#include "reftable-blocksource.h"
++#include "reftable-error.h"
++#include "reftable-merged.h"
++#include "reftable-record.h"
+ #include "reftable-tests.h"
++#include "reftable-writer.h"
++#include "reftable-iterator.h"
++#include "reftable-reader.h"
++#include "reftable-stack.h"
- err = reftable_table_seek_ref(&fri->tab, &it,
- ref->refname);
-
- ## reftable/reader.c ##
-@@ reftable/reader.c: static int parse_footer(struct reftable_reader *r, uint8_t *footer,
- int init_reader(struct reftable_reader *r, struct reftable_block_source *source,
- const char *name)
- {
-- struct reftable_block footer = { 0 };
-- struct reftable_block header = { 0 };
-+ struct reftable_block footer = { NULL };
-+ struct reftable_block header = { NULL };
- int err = 0;
+ static uint32_t hash_id;
- memset(r, 0, sizeof(struct reftable_reader));
-@@ reftable/reader.c: int reader_init_block_reader(struct reftable_reader *r, struct block_reader *br,
+ static int dump_table(const char *tablename)
{
- int32_t guess_block_size = r->block_size ? r->block_size :
- DEFAULT_BLOCK_SIZE;
-- struct reftable_block block = { 0 };
-+ struct reftable_block block = { NULL };
- uint8_t block_typ = 0;
- int err = 0;
- uint32_t header_off = next_off ? 0 : header_size(r->version);
-@@ reftable/reader.c: static int reader_seek_indexed(struct reftable_reader *r,
- struct reftable_record *rec)
+- struct reftable_block_source src = { 0 };
++ struct reftable_block_source src = { NULL };
+ int err = reftable_block_source_from_file(&src, tablename);
+- struct reftable_iterator it = { 0 };
+- struct reftable_ref_record ref = { 0 };
+- struct reftable_log_record log = { 0 };
++ struct reftable_iterator it = { NULL };
++ struct reftable_ref_record ref = { NULL };
++ struct reftable_log_record log = { NULL };
+ struct reftable_reader *r = NULL;
+
+ if (err < 0)
+@@ reftable/dump.c: static int dump_table(const char *tablename)
+ reftable_ref_record_print(&ref, hash_id);
+ }
+ reftable_iterator_destroy(&it);
+- reftable_ref_record_clear(&ref);
++ reftable_ref_record_release(&ref);
+
+ err = reftable_reader_seek_log(r, &it, "");
+ if (err < 0) {
+@@ reftable/dump.c: static int dump_table(const char *tablename)
+ reftable_log_record_print(&log, hash_id);
+ }
+ reftable_iterator_destroy(&it);
+- reftable_log_record_clear(&log);
++ reftable_log_record_release(&log);
+
+ reftable_reader_free(r);
+ return 0;
+@@ reftable/dump.c: static int dump_stack(const char *stackdir)
{
- struct reftable_index_record want_index = { .last_key = STRBUF_INIT };
-- struct reftable_record want_index_rec = { 0 };
-+ struct reftable_record want_index_rec = { NULL };
- struct reftable_index_record index_result = { .last_key = STRBUF_INIT };
-- struct reftable_record index_result_rec = { 0 };
-+ struct reftable_record index_result_rec = { NULL };
- struct table_iter index_iter = TABLE_ITER_INIT;
- struct table_iter next = TABLE_ITER_INIT;
- int err = 0;
-@@ reftable/reader.c: int reftable_reader_seek_ref(struct reftable_reader *r,
- struct reftable_ref_record ref = {
- .refname = (char *)name,
- };
-- struct reftable_record rec = { 0 };
-+ struct reftable_record rec = { NULL };
- reftable_record_from_ref(&rec, &ref);
- return reader_seek(r, it, &rec);
- }
-@@ reftable/reader.c: int reftable_reader_seek_log_at(struct reftable_reader *r,
- .refname = (char *)name,
- .update_index = update_index,
- };
-- struct reftable_record rec = { 0 };
-+ struct reftable_record rec = { NULL };
- reftable_record_from_log(&rec, &log);
- return reader_seek(r, it, &rec);
- }
-@@ reftable/reader.c: static int reftable_reader_refs_for_indexed(struct reftable_reader *r,
- .hash_prefix = oid,
- .hash_prefix_len = r->object_id_len,
- };
-- struct reftable_record want_rec = { 0 };
-- struct reftable_iterator oit = { 0 };
-- struct reftable_obj_record got = { 0 };
-- struct reftable_record got_rec = { 0 };
-+ struct reftable_record want_rec = { NULL };
-+ struct reftable_iterator oit = { NULL };
-+ struct reftable_obj_record got = { NULL };
-+ struct reftable_record got_rec = { NULL };
- int err = 0;
- struct indexed_table_ref_iter *itr = NULL;
+ 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_iterator it = { NULL };
++ struct reftable_ref_record ref = { NULL };
++ struct reftable_log_record log = { NULL };
+ struct reftable_merged_table *merged = NULL;
+ int err = reftable_new_stack(&stack, stackdir, cfg);
+@@ reftable/dump.c: static int dump_stack(const char *stackdir)
+ reftable_ref_record_print(&ref, hash_id);
+ }
+ reftable_iterator_destroy(&it);
+- reftable_ref_record_clear(&ref);
++ reftable_ref_record_release(&ref);
+
+ err = reftable_merged_table_seek_log(merged, &it, "");
+ if (err < 0) {
+@@ reftable/dump.c: static int dump_stack(const char *stackdir)
+ reftable_log_record_print(&log, hash_id);
+ }
+ reftable_iterator_destroy(&it);
+- reftable_log_record_clear(&log);
++ reftable_log_record_release(&log);
+
+ reftable_stack_destroy(stack);
+ return 0;
## t/helper/test-reftable.c ##
@@ t/helper/test-reftable.c: int cmd__reftable(int argc, const char **argv)
@@ t/helper/test-tool.h: int cmd__dump_cache_tree(int argc, const char **argv);
int cmd__dump_untracked_cache(int argc, const char **argv);
+int cmd__dump_reftable(int argc, const char **argv);
int cmd__example_decorate(int argc, const char **argv);
+ int cmd__fast_rebase(int argc, const char **argv);
int cmd__genrandom(int argc, const char **argv);
- int cmd__genzeros(int argc, const char **argv);
--
gitgitgadget
next prev parent reply other threads:[~2020-11-26 19:44 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 ` Han-Wen Nienhuys via GitGitGadget [this message]
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 ` [PATCH v4 00/15] reftable library Han-Wen Nienhuys via GitGitGadget
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.v3.git.git.1606419752.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=Johannes.Schindelin@gmx.de \
--cc=avarab@gmail.com \
--cc=emilyshaffer@google.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).