Merge pull request #29241 from bfredl/shadapack

refactor(shada): use msgpack_sbuffer less
This commit is contained in:
bfredl
2024-06-14 11:33:27 +02:00
committed by GitHub
13 changed files with 176 additions and 206 deletions

View File

@@ -548,10 +548,6 @@ String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col
void api_free_string(String value) void api_free_string(String value)
{ {
if (!value.data) {
return;
}
xfree(value.data); xfree(value.data);
} }

View File

@@ -66,21 +66,11 @@ Context *ctx_get(size_t index)
void ctx_free(Context *ctx) void ctx_free(Context *ctx)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
if (ctx->regs.data) { api_free_string(ctx->regs);
msgpack_sbuffer_destroy(&ctx->regs); api_free_string(ctx->jumps);
} api_free_string(ctx->bufs);
if (ctx->jumps.data) { api_free_string(ctx->gvars);
msgpack_sbuffer_destroy(&ctx->jumps); api_free_array(ctx->funcs);
}
if (ctx->bufs.data) {
msgpack_sbuffer_destroy(&ctx->bufs);
}
if (ctx->gvars.data) {
msgpack_sbuffer_destroy(&ctx->gvars);
}
if (ctx->funcs.items) {
api_free_array(ctx->funcs);
}
} }
/// Saves the editor state to a context. /// Saves the editor state to a context.
@@ -98,19 +88,19 @@ void ctx_save(Context *ctx, const int flags)
} }
if (flags & kCtxRegs) { if (flags & kCtxRegs) {
ctx_save_regs(ctx); ctx->regs = shada_encode_regs();
} }
if (flags & kCtxJumps) { if (flags & kCtxJumps) {
ctx_save_jumps(ctx); ctx->jumps = shada_encode_jumps();
} }
if (flags & kCtxBufs) { if (flags & kCtxBufs) {
ctx_save_bufs(ctx); ctx->bufs = shada_encode_buflist();
} }
if (flags & kCtxGVars) { if (flags & kCtxGVars) {
ctx_save_gvars(ctx); ctx->gvars = shada_encode_gvars();
} }
if (flags & kCtxFuncs) { if (flags & kCtxFuncs) {
@@ -173,33 +163,13 @@ bool ctx_restore(Context *ctx, const int flags)
return true; return true;
} }
/// Saves the global registers to a context.
///
/// @param ctx Save to this context.
static inline void ctx_save_regs(Context *ctx)
FUNC_ATTR_NONNULL_ALL
{
msgpack_sbuffer_init(&ctx->regs);
shada_encode_regs(&ctx->regs);
}
/// Restores the global registers from a context. /// Restores the global registers from a context.
/// ///
/// @param ctx Restore from this context. /// @param ctx Restore from this context.
static inline void ctx_restore_regs(Context *ctx) static inline void ctx_restore_regs(Context *ctx)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
shada_read_sbuf(&ctx->regs, kShaDaWantInfo | kShaDaForceit); shada_read_string(ctx->regs, kShaDaWantInfo | kShaDaForceit);
}
/// Saves the jumplist to a context.
///
/// @param ctx Save to this context.
static inline void ctx_save_jumps(Context *ctx)
FUNC_ATTR_NONNULL_ALL
{
msgpack_sbuffer_init(&ctx->jumps);
shada_encode_jumps(&ctx->jumps);
} }
/// Restores the jumplist from a context. /// Restores the jumplist from a context.
@@ -208,17 +178,7 @@ static inline void ctx_save_jumps(Context *ctx)
static inline void ctx_restore_jumps(Context *ctx) static inline void ctx_restore_jumps(Context *ctx)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
shada_read_sbuf(&ctx->jumps, kShaDaWantInfo | kShaDaForceit); shada_read_string(ctx->jumps, kShaDaWantInfo | kShaDaForceit);
}
/// Saves the buffer list to a context.
///
/// @param ctx Save to this context.
static inline void ctx_save_bufs(Context *ctx)
FUNC_ATTR_NONNULL_ALL
{
msgpack_sbuffer_init(&ctx->bufs);
shada_encode_buflist(&ctx->bufs);
} }
/// Restores the buffer list from a context. /// Restores the buffer list from a context.
@@ -227,17 +187,7 @@ static inline void ctx_save_bufs(Context *ctx)
static inline void ctx_restore_bufs(Context *ctx) static inline void ctx_restore_bufs(Context *ctx)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
shada_read_sbuf(&ctx->bufs, kShaDaWantInfo | kShaDaForceit); shada_read_string(ctx->bufs, kShaDaWantInfo | kShaDaForceit);
}
/// Saves global variables to a context.
///
/// @param ctx Save to this context.
static inline void ctx_save_gvars(Context *ctx)
FUNC_ATTR_NONNULL_ALL
{
msgpack_sbuffer_init(&ctx->gvars);
shada_encode_gvars(&ctx->gvars);
} }
/// Restores global variables from a context. /// Restores global variables from a context.
@@ -246,7 +196,7 @@ static inline void ctx_save_gvars(Context *ctx)
static inline void ctx_restore_gvars(Context *ctx) static inline void ctx_restore_gvars(Context *ctx)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
shada_read_sbuf(&ctx->gvars, kShaDaWantInfo | kShaDaForceit); shada_read_string(ctx->gvars, kShaDaWantInfo | kShaDaForceit);
} }
/// Saves functions to a context. /// Saves functions to a context.
@@ -291,41 +241,16 @@ static inline void ctx_restore_funcs(Context *ctx)
} }
} }
/// Convert msgpack_sbuffer to readfile()-style array. /// Convert readfile()-style array to String
///
/// @param[in] sbuf msgpack_sbuffer to convert.
///
/// @return readfile()-style array representation of "sbuf".
static inline Array sbuf_to_array(msgpack_sbuffer sbuf, Arena *arena)
{
list_T *const list = tv_list_alloc(kListLenMayKnow);
tv_list_append_string(list, "", 0);
if (sbuf.size > 0) {
encode_list_write(list, sbuf.data, sbuf.size);
}
typval_T list_tv = (typval_T) {
.v_lock = VAR_UNLOCKED,
.v_type = VAR_LIST,
.vval.v_list = list
};
Array array = vim_to_object(&list_tv, arena, false).data.array;
tv_clear(&list_tv);
return array;
}
/// Convert readfile()-style array to msgpack_sbuffer.
/// ///
/// @param[in] array readfile()-style array to convert. /// @param[in] array readfile()-style array to convert.
/// @param[out] err Error object. /// @param[out] err Error object.
/// ///
/// @return msgpack_sbuffer with conversion result. /// @return String with conversion result.
static inline msgpack_sbuffer array_to_sbuf(Array array, Error *err) static inline String array_to_string(Array array, Error *err)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
msgpack_sbuffer sbuf; String sbuf = STRING_INIT;
msgpack_sbuffer_init(&sbuf);
typval_T list_tv; typval_T list_tv;
object_to_vim(ARRAY_OBJ(array), &list_tv, err); object_to_vim(ARRAY_OBJ(array), &list_tv, err);
@@ -335,7 +260,6 @@ static inline msgpack_sbuffer array_to_sbuf(Array array, Error *err)
api_set_error(err, kErrorTypeException, "%s", api_set_error(err, kErrorTypeException, "%s",
"E474: Failed to convert list to msgpack string buffer"); "E474: Failed to convert list to msgpack string buffer");
} }
sbuf.alloc = sbuf.size;
tv_clear(&list_tv); tv_clear(&list_tv);
return sbuf; return sbuf;
@@ -353,10 +277,10 @@ Dictionary ctx_to_dict(Context *ctx, Arena *arena)
Dictionary rv = arena_dict(arena, 5); Dictionary rv = arena_dict(arena, 5);
PUT_C(rv, "regs", ARRAY_OBJ(sbuf_to_array(ctx->regs, arena))); PUT_C(rv, "regs", ARRAY_OBJ(string_to_array(ctx->regs, false, arena)));
PUT_C(rv, "jumps", ARRAY_OBJ(sbuf_to_array(ctx->jumps, arena))); PUT_C(rv, "jumps", ARRAY_OBJ(string_to_array(ctx->jumps, false, arena)));
PUT_C(rv, "bufs", ARRAY_OBJ(sbuf_to_array(ctx->bufs, arena))); PUT_C(rv, "bufs", ARRAY_OBJ(string_to_array(ctx->bufs, false, arena)));
PUT_C(rv, "gvars", ARRAY_OBJ(sbuf_to_array(ctx->gvars, arena))); PUT_C(rv, "gvars", ARRAY_OBJ(string_to_array(ctx->gvars, false, arena)));
PUT_C(rv, "funcs", ARRAY_OBJ(copy_array(ctx->funcs, arena))); PUT_C(rv, "funcs", ARRAY_OBJ(copy_array(ctx->funcs, arena)));
return rv; return rv;
@@ -382,16 +306,16 @@ int ctx_from_dict(Dictionary dict, Context *ctx, Error *err)
} }
if (strequal(item.key.data, "regs")) { if (strequal(item.key.data, "regs")) {
types |= kCtxRegs; types |= kCtxRegs;
ctx->regs = array_to_sbuf(item.value.data.array, err); ctx->regs = array_to_string(item.value.data.array, err);
} else if (strequal(item.key.data, "jumps")) { } else if (strequal(item.key.data, "jumps")) {
types |= kCtxJumps; types |= kCtxJumps;
ctx->jumps = array_to_sbuf(item.value.data.array, err); ctx->jumps = array_to_string(item.value.data.array, err);
} else if (strequal(item.key.data, "bufs")) { } else if (strequal(item.key.data, "bufs")) {
types |= kCtxBufs; types |= kCtxBufs;
ctx->bufs = array_to_sbuf(item.value.data.array, err); ctx->bufs = array_to_string(item.value.data.array, err);
} else if (strequal(item.key.data, "gvars")) { } else if (strequal(item.key.data, "gvars")) {
types |= kCtxGVars; types |= kCtxGVars;
ctx->gvars = array_to_sbuf(item.value.data.array, err); ctx->gvars = array_to_string(item.value.data.array, err);
} else if (strequal(item.key.data, "funcs")) { } else if (strequal(item.key.data, "funcs")) {
types |= kCtxFuncs; types |= kCtxFuncs;
ctx->funcs = copy_object(item.value, NULL).data.array; ctx->funcs = copy_object(item.value, NULL).data.array;

View File

@@ -7,25 +7,19 @@
#include "nvim/api/private/defs.h" #include "nvim/api/private/defs.h"
typedef struct { typedef struct {
msgpack_sbuffer regs; ///< Registers. String regs; ///< Registers.
msgpack_sbuffer jumps; ///< Jumplist. String jumps; ///< Jumplist.
msgpack_sbuffer bufs; ///< Buffer list. String bufs; ///< Buffer list.
msgpack_sbuffer gvars; ///< Global variables. String gvars; ///< Global variables.
Array funcs; ///< Functions. Array funcs; ///< Functions.
} Context; } Context;
typedef kvec_t(Context) ContextVec; typedef kvec_t(Context) ContextVec;
#define MSGPACK_SBUFFER_INIT (msgpack_sbuffer) { \
.size = 0, \
.data = NULL, \
.alloc = 0, \
}
#define CONTEXT_INIT (Context) { \ #define CONTEXT_INIT (Context) { \
.regs = MSGPACK_SBUFFER_INIT, \ .regs = STRING_INIT, \
.jumps = MSGPACK_SBUFFER_INIT, \ .jumps = STRING_INIT, \
.bufs = MSGPACK_SBUFFER_INIT, \ .bufs = STRING_INIT, \
.gvars = MSGPACK_SBUFFER_INIT, \ .gvars = STRING_INIT, \
.funcs = ARRAY_DICT_INIT, \ .funcs = ARRAY_DICT_INIT, \
} }

View File

@@ -45,8 +45,6 @@ EXTERN size_t arena_alloc_count INIT( = 0);
((v).capacity = (s), \ ((v).capacity = (s), \
(v).items = (void *)arena_alloc(a, sizeof((v).items[0]) * (v).capacity, true)) (v).items = (void *)arena_alloc(a, sizeof((v).items[0]) * (v).capacity, true))
#define ARENA_BLOCK_SIZE 4096
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "memory.h.generated.h" # include "memory.h.generated.h"
#endif #endif

View File

@@ -11,5 +11,7 @@ typedef struct {
size_t pos, size; size_t pos, size;
} Arena; } Arena;
#define ARENA_BLOCK_SIZE 4096
// inits an empty arena. // inits an empty arena.
#define ARENA_EMPTY { .cur_blk = NULL, .pos = 0, .size = 0 } #define ARENA_EMPTY { .cur_blk = NULL, .pos = 0, .size = 0 }

View File

@@ -590,16 +590,16 @@ static void packer_buffer_init_channels(Channel **chans, size_t nchans, PackerBu
packer->endptr = packer->startptr + ARENA_BLOCK_SIZE; packer->endptr = packer->startptr + ARENA_BLOCK_SIZE;
packer->packer_flush = channel_flush_callback; packer->packer_flush = channel_flush_callback;
packer->anydata = chans; packer->anydata = chans;
packer->anylen = nchans; packer->anyint = (int64_t)nchans;
} }
static void packer_buffer_finish_channels(PackerBuffer *packer) static void packer_buffer_finish_channels(PackerBuffer *packer)
{ {
size_t len = (size_t)(packer->ptr - packer->startptr); size_t len = (size_t)(packer->ptr - packer->startptr);
if (len > 0) { if (len > 0) {
WBuffer *buf = wstream_new_buffer(packer->startptr, len, packer->anylen, free_block); WBuffer *buf = wstream_new_buffer(packer->startptr, len, (size_t)packer->anyint, free_block);
Channel **chans = packer->anydata; Channel **chans = packer->anydata;
for (size_t i = 0; i < packer->anylen; i++) { for (int64_t i = 0; i < packer->anyint; i++) {
channel_write(chans[i], buf); channel_write(chans[i], buf);
} }
} else { } else {
@@ -610,7 +610,7 @@ static void packer_buffer_finish_channels(PackerBuffer *packer)
static void channel_flush_callback(PackerBuffer *packer) static void channel_flush_callback(PackerBuffer *packer)
{ {
packer_buffer_finish_channels(packer); packer_buffer_finish_channels(packer);
packer_buffer_init_channels(packer->anydata, packer->anylen, packer); packer_buffer_init_channels(packer->anydata, (size_t)packer->anyint, packer);
} }
void rpc_set_client_info(uint64_t id, Dictionary info) void rpc_set_client_info(uint64_t id, Dictionary info)

View File

@@ -10,8 +10,7 @@
static void check_buffer(PackerBuffer *packer) static void check_buffer(PackerBuffer *packer)
{ {
ptrdiff_t remaining = packer->endptr - packer->ptr; if (mpack_remaining(packer) < MPACK_ITEM_SIZE) {
if (remaining < MPACK_ITEM_SIZE) {
packer->packer_flush(packer); packer->packer_flush(packer);
} }
} }
@@ -28,15 +27,20 @@ static void mpack_w8(char **b, const char *data)
#endif #endif
} }
void mpack_uint64(char **ptr, uint64_t i)
{
if (i > 0xfffffff) {
mpack_w(ptr, 0xcf);
mpack_w8(ptr, (char *)&i);
} else {
mpack_uint(ptr, (uint32_t)i);
}
}
void mpack_integer(char **ptr, Integer i) void mpack_integer(char **ptr, Integer i)
{ {
if (i >= 0) { if (i >= 0) {
if (i > 0xfffffff) { mpack_uint64(ptr, (uint64_t)i);
mpack_w(ptr, 0xcf);
mpack_w8(ptr, (char *)&i);
} else {
mpack_uint(ptr, (uint32_t)i);
}
} else { } else {
if (i < -0x80000000LL) { if (i < -0x80000000LL) {
mpack_w(ptr, 0xd3); mpack_w(ptr, 0xd3);
@@ -80,11 +84,16 @@ void mpack_str(String str, PackerBuffer *packer)
abort(); abort();
} }
mpack_raw(str.data, len, packer);
}
void mpack_raw(char *data, size_t len, PackerBuffer *packer)
{
size_t pos = 0; size_t pos = 0;
while (pos < len) { while (pos < len) {
ptrdiff_t remaining = packer->endptr - packer->ptr; ptrdiff_t remaining = packer->endptr - packer->ptr;
size_t to_copy = MIN(len - pos, (size_t)remaining); size_t to_copy = MIN(len - pos, (size_t)remaining);
memcpy(packer->ptr, str.data + pos, to_copy); memcpy(packer->ptr, data + pos, to_copy);
packer->ptr += to_copy; packer->ptr += to_copy;
pos += to_copy; pos += to_copy;

View File

@@ -71,6 +71,11 @@ static inline void mpack_map(char **buf, uint32_t len)
} }
} }
static inline size_t mpack_remaining(PackerBuffer *packer)
{
return (size_t)(packer->endptr - packer->ptr);
}
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "msgpack_rpc/packer.h.generated.h" # include "msgpack_rpc/packer.h.generated.h"
#endif #endif

View File

@@ -19,6 +19,6 @@ struct packer_buffer_t {
// these are free to be used by packer_flush for any purpose, if want // these are free to be used by packer_flush for any purpose, if want
void *anydata; void *anydata;
size_t anylen; int64_t anyint;
PackerBufferFlush packer_flush; PackerBufferFlush packer_flush;
}; };

View File

@@ -320,9 +320,8 @@ ptrdiff_t file_write(FileDescriptor *const fp, const char *const buf, const size
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{ {
assert(fp->wr); assert(fp->wr);
ptrdiff_t space = (fp->buffer + ARENA_BLOCK_SIZE) - fp->write_pos;
// includes the trivial case of size==0 // includes the trivial case of size==0
if (size < (size_t)space) { if (size < file_space(fp)) {
memcpy(fp->write_pos, buf, size); memcpy(fp->write_pos, buf, size);
fp->write_pos += size; fp->write_pos += size;
return (ptrdiff_t)size; return (ptrdiff_t)size;

View File

@@ -2,6 +2,7 @@
#include <stddef.h> // IWYU pragma: keep #include <stddef.h> // IWYU pragma: keep
#include "nvim/memory_defs.h"
#include "nvim/os/fileio_defs.h" // IWYU pragma: keep #include "nvim/os/fileio_defs.h" // IWYU pragma: keep
/// file_open() flags /// file_open() flags
@@ -32,6 +33,11 @@ enum {
kRWBufferSize = 1024, kRWBufferSize = 1024,
}; };
static inline size_t file_space(FileDescriptor *fp)
{
return (size_t)((fp->buffer + ARENA_BLOCK_SIZE) - fp->write_pos);
}
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/fileio.h.generated.h" # include "os/fileio.h.generated.h"
#endif #endif

View File

@@ -42,6 +42,7 @@
#include "nvim/mbyte.h" #include "nvim/mbyte.h"
#include "nvim/memory.h" #include "nvim/memory.h"
#include "nvim/message.h" #include "nvim/message.h"
#include "nvim/msgpack_rpc/packer.h"
#include "nvim/normal_defs.h" #include "nvim/normal_defs.h"
#include "nvim/ops.h" #include "nvim/ops.h"
#include "nvim/option.h" #include "nvim/option.h"
@@ -602,20 +603,6 @@ static void close_file(FileDescriptor *cookie)
} }
} }
/// Msgpack callback for writing to FileDescriptor*
static int msgpack_sd_writer_write(void *data, const char *buf, size_t len)
{
FileDescriptor *const sd_writer = (FileDescriptor *)data;
const ptrdiff_t ret = file_write(sd_writer, buf, len);
if (ret < 0) {
semsg(_(SERR "System error while writing ShaDa file: %s"),
os_strerror((int)ret));
return -1;
}
return 0;
}
/// Check whether writing to shada file was disabled ("-i NONE" or "--clean"). /// Check whether writing to shada file was disabled ("-i NONE" or "--clean").
/// ///
/// @return true if it was disabled, false otherwise. /// @return true if it was disabled, false otherwise.
@@ -1365,6 +1352,8 @@ static char *shada_filename(const char *file)
} \ } \
} while (0) } while (0)
#define SHADA_MPACK_FREE_SPACE (4 * MPACK_ITEM_SIZE)
/// Write single ShaDa entry /// Write single ShaDa entry
/// ///
/// @param[in] packer Packer used to write entry. /// @param[in] packer Packer used to write entry.
@@ -1373,7 +1362,7 @@ static char *shada_filename(const char *file)
/// restrictions. /// restrictions.
/// ///
/// @return kSDWriteSuccessful, kSDWriteFailed or kSDWriteIgnError. /// @return kSDWriteSuccessful, kSDWriteFailed or kSDWriteIgnError.
static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, ShadaEntry entry, static ShaDaWriteResult shada_pack_entry(PackerBuffer *const packer, ShadaEntry entry,
const size_t max_kbyte) const size_t max_kbyte)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
@@ -1657,29 +1646,26 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, ShadaEntr
#undef CHECK_DEFAULT #undef CHECK_DEFAULT
#undef ONE_IF_NOT_DEFAULT #undef ONE_IF_NOT_DEFAULT
if (!max_kbyte || sbuf.size <= max_kbyte * 1024) { if (!max_kbyte || sbuf.size <= max_kbyte * 1024) {
if (entry.type == kSDItemUnknown) { if (mpack_remaining(packer) < SHADA_MPACK_FREE_SPACE) {
if (msgpack_pack_uint64(packer, entry.data.unknown_item.type) == -1) { packer->packer_flush(packer);
goto shada_pack_entry_error;
}
} else {
if (msgpack_pack_uint64(packer, (uint64_t)entry.type) == -1) {
goto shada_pack_entry_error;
}
} }
if (msgpack_pack_uint64(packer, (uint64_t)entry.timestamp) == -1) {
if (entry.type == kSDItemUnknown) {
mpack_uint64(&packer->ptr, entry.data.unknown_item.type);
} else {
mpack_uint64(&packer->ptr, (uint64_t)entry.type);
}
mpack_uint64(&packer->ptr, (uint64_t)entry.timestamp);
if (sbuf.size > 0) {
mpack_uint64(&packer->ptr, (uint64_t)sbuf.size);
mpack_raw(sbuf.data, sbuf.size, packer);
}
if (packer->anyint != 0) { // error code
goto shada_pack_entry_error; goto shada_pack_entry_error;
} }
if (sbuf.size > 0) {
if ((msgpack_pack_uint64(packer, (uint64_t)sbuf.size) == -1)
|| (packer->callback(packer->data, sbuf.data,
(unsigned)sbuf.size) == -1)) {
goto shada_pack_entry_error;
}
}
} }
msgpack_packer_free(spacker); ret = kSDWriteSuccessful;
msgpack_sbuffer_destroy(&sbuf);
return kSDWriteSuccessful;
shada_pack_entry_error: shada_pack_entry_error:
msgpack_packer_free(spacker); msgpack_packer_free(spacker);
msgpack_sbuffer_destroy(&sbuf); msgpack_sbuffer_destroy(&sbuf);
@@ -1694,7 +1680,7 @@ shada_pack_entry_error:
/// @param[in] entry Entry written. /// @param[in] entry Entry written.
/// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no /// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no
/// restrictions. /// restrictions.
static inline ShaDaWriteResult shada_pack_pfreed_entry(msgpack_packer *const packer, static inline ShaDaWriteResult shada_pack_pfreed_entry(PackerBuffer *const packer,
PossiblyFreedShadaEntry entry, PossiblyFreedShadaEntry entry,
const size_t max_kbyte) const size_t max_kbyte)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
@@ -1908,7 +1894,7 @@ static inline ShaDaWriteResult shada_read_when_writing(FileDescriptor *const sd_
const unsigned srni_flags, const unsigned srni_flags,
const size_t max_kbyte, const size_t max_kbyte,
WriteMergerState *const wms, WriteMergerState *const wms,
msgpack_packer *const packer) PackerBuffer *const packer)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{ {
ShaDaWriteResult ret = kSDWriteSuccessful; ShaDaWriteResult ret = kSDWriteSuccessful;
@@ -2360,6 +2346,29 @@ static int hist_type2char(const int type)
return NUL; return NUL;
} }
static PackerBuffer packer_buffer_for_file(FileDescriptor *file)
{
if (file_space(file) < SHADA_MPACK_FREE_SPACE) {
file_flush(file);
}
return (PackerBuffer) {
.startptr = file->buffer,
.ptr = file->write_pos,
.endptr = file->buffer + ARENA_BLOCK_SIZE,
.anydata = file,
.anyint = 0, // set to nonzero if error
.packer_flush = flush_file_buffer,
};
}
static void flush_file_buffer(PackerBuffer *buffer)
{
FileDescriptor *fd = buffer->anydata;
fd->write_pos = buffer->ptr;
buffer->anyint = file_flush(fd);
buffer->ptr = fd->write_pos;
}
/// Write ShaDa file /// Write ShaDa file
/// ///
/// @param[in] sd_writer Structure containing file writer definition. /// @param[in] sd_writer Structure containing file writer definition.
@@ -2408,8 +2417,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
} }
} }
const unsigned srni_flags = (unsigned)( const unsigned srni_flags = (unsigned)(kSDReadUndisableableData
kSDReadUndisableableData
| kSDReadUnknown | kSDReadUnknown
| (dump_history ? kSDReadHistory : 0) | (dump_history ? kSDReadHistory : 0)
| (dump_registers ? kSDReadRegisters : 0) | (dump_registers ? kSDReadRegisters : 0)
@@ -2418,8 +2426,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
| (num_marked_files ? kSDReadLocalMarks | | (num_marked_files ? kSDReadLocalMarks |
kSDReadChanges : 0)); kSDReadChanges : 0));
msgpack_packer *const packer = msgpack_packer_new(sd_writer, PackerBuffer packer = packer_buffer_for_file(sd_writer);
&msgpack_sd_writer_write);
// Set b_last_cursor for all the buffers that have a window. // Set b_last_cursor for all the buffers that have a window.
// //
@@ -2433,7 +2440,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
find_removable_bufs(&removable_bufs); find_removable_bufs(&removable_bufs);
// Write header // Write header
if (shada_pack_entry(packer, (ShadaEntry) { if (shada_pack_entry(&packer, (ShadaEntry) {
.type = kSDItemHeader, .type = kSDItemHeader,
.timestamp = os_time(), .timestamp = os_time(),
.data = { .data = {
@@ -2462,7 +2469,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
// Write buffer list // Write buffer list
if (find_shada_parameter('%') != NULL) { if (find_shada_parameter('%') != NULL) {
ShadaEntry buflist_entry = shada_get_buflist(&removable_bufs); ShadaEntry buflist_entry = shada_get_buflist(&removable_bufs);
if (shada_pack_entry(packer, buflist_entry, 0) == kSDWriteFailed) { if (shada_pack_entry(&packer, buflist_entry, 0) == kSDWriteFailed) {
xfree(buflist_entry.data.buffer_list.buffers); xfree(buflist_entry.data.buffer_list.buffers);
ret = kSDWriteFailed; ret = kSDWriteFailed;
goto shada_write_exit; goto shada_write_exit;
@@ -2512,7 +2519,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
typval_T tgttv; typval_T tgttv;
tv_copy(&vartv, &tgttv); tv_copy(&vartv, &tgttv);
ShaDaWriteResult spe_ret; ShaDaWriteResult spe_ret;
if ((spe_ret = shada_pack_entry(packer, (ShadaEntry) { if ((spe_ret = shada_pack_entry(&packer, (ShadaEntry) {
.type = kSDItemVariable, .type = kSDItemVariable,
.timestamp = cur_timestamp, .timestamp = cur_timestamp,
.data = { .data = {
@@ -2689,7 +2696,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
if (sd_reader != NULL) { if (sd_reader != NULL) {
const ShaDaWriteResult srww_ret = shada_read_when_writing(sd_reader, srni_flags, max_kbyte, wms, const ShaDaWriteResult srww_ret = shada_read_when_writing(sd_reader, srni_flags, max_kbyte, wms,
packer); &packer);
if (srww_ret != kSDWriteSuccessful) { if (srww_ret != kSDWriteSuccessful) {
ret = srww_ret; ret = srww_ret;
} }
@@ -2720,7 +2727,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
do { \ do { \
for (size_t i_ = 0; i_ < ARRAY_SIZE(wms_array); i_++) { \ for (size_t i_ = 0; i_ < ARRAY_SIZE(wms_array); i_++) { \
if ((wms_array)[i_].data.type != kSDItemMissing) { \ if ((wms_array)[i_].data.type != kSDItemMissing) { \
if (shada_pack_pfreed_entry(packer, (wms_array)[i_], max_kbyte) \ if (shada_pack_pfreed_entry(&packer, (wms_array)[i_], max_kbyte) \
== kSDWriteFailed) { \ == kSDWriteFailed) { \
ret = kSDWriteFailed; \ ret = kSDWriteFailed; \
goto shada_write_exit; \ goto shada_write_exit; \
@@ -2732,7 +2739,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
PACK_WMS_ARRAY(wms->numbered_marks); PACK_WMS_ARRAY(wms->numbered_marks);
PACK_WMS_ARRAY(wms->registers); PACK_WMS_ARRAY(wms->registers);
for (size_t i = 0; i < wms->jumps_size; i++) { for (size_t i = 0; i < wms->jumps_size; i++) {
if (shada_pack_pfreed_entry(packer, wms->jumps[i], max_kbyte) if (shada_pack_pfreed_entry(&packer, wms->jumps[i], max_kbyte)
== kSDWriteFailed) { == kSDWriteFailed) {
ret = kSDWriteFailed; ret = kSDWriteFailed;
goto shada_write_exit; goto shada_write_exit;
@@ -2741,7 +2748,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
#define PACK_WMS_ENTRY(wms_entry) \ #define PACK_WMS_ENTRY(wms_entry) \
do { \ do { \
if ((wms_entry).data.type != kSDItemMissing) { \ if ((wms_entry).data.type != kSDItemMissing) { \
if (shada_pack_pfreed_entry(packer, wms_entry, max_kbyte) \ if (shada_pack_pfreed_entry(&packer, wms_entry, max_kbyte) \
== kSDWriteFailed) { \ == kSDWriteFailed) { \
ret = kSDWriteFailed; \ ret = kSDWriteFailed; \
goto shada_write_exit; \ goto shada_write_exit; \
@@ -2767,14 +2774,14 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
for (size_t i = 0; i < file_markss_to_dump; i++) { for (size_t i = 0; i < file_markss_to_dump; i++) {
PACK_WMS_ARRAY(all_file_markss[i]->marks); PACK_WMS_ARRAY(all_file_markss[i]->marks);
for (size_t j = 0; j < all_file_markss[i]->changes_size; j++) { for (size_t j = 0; j < all_file_markss[i]->changes_size; j++) {
if (shada_pack_pfreed_entry(packer, all_file_markss[i]->changes[j], if (shada_pack_pfreed_entry(&packer, all_file_markss[i]->changes[j],
max_kbyte) == kSDWriteFailed) { max_kbyte) == kSDWriteFailed) {
ret = kSDWriteFailed; ret = kSDWriteFailed;
goto shada_write_exit; goto shada_write_exit;
} }
} }
for (size_t j = 0; j < all_file_markss[i]->additional_marks_size; j++) { for (size_t j = 0; j < all_file_markss[i]->additional_marks_size; j++) {
if (shada_pack_entry(packer, all_file_markss[i]->additional_marks[j], if (shada_pack_entry(&packer, all_file_markss[i]->additional_marks[j],
0) == kSDWriteFailed) { 0) == kSDWriteFailed) {
shada_free_shada_entry(&all_file_markss[i]->additional_marks[j]); shada_free_shada_entry(&all_file_markss[i]->additional_marks[j]);
ret = kSDWriteFailed; ret = kSDWriteFailed;
@@ -2792,7 +2799,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
if (dump_one_history[i]) { if (dump_one_history[i]) {
hms_insert_whole_neovim_history(&wms->hms[i]); hms_insert_whole_neovim_history(&wms->hms[i]);
HMS_ITER(&wms->hms[i], cur_entry, { HMS_ITER(&wms->hms[i], cur_entry, {
if (shada_pack_pfreed_entry(packer, (PossiblyFreedShadaEntry) { if (shada_pack_pfreed_entry(&packer, (PossiblyFreedShadaEntry) {
.data = cur_entry->data, .data = cur_entry->data,
.can_free_entry = cur_entry->can_free_entry, .can_free_entry = cur_entry->can_free_entry,
}, max_kbyte) == kSDWriteFailed) { }, max_kbyte) == kSDWriteFailed) {
@@ -2818,7 +2825,7 @@ shada_write_exit:
}) })
map_destroy(cstr_t, &wms->file_marks); map_destroy(cstr_t, &wms->file_marks);
set_destroy(ptr_t, &removable_bufs); set_destroy(ptr_t, &removable_bufs);
msgpack_packer_free(packer); packer.packer_flush(&packer);
set_destroy(cstr_t, &wms->dumped_variables); set_destroy(cstr_t, &wms->dumped_variables);
xfree(wms); xfree(wms);
return ret; return ret;
@@ -3953,16 +3960,43 @@ static inline size_t shada_init_jumps(PossiblyFreedShadaEntry *jumps,
return jumps_size; return jumps_size;
} }
static PackerBuffer packer_string_buffer(void)
{
const size_t initial_size = 64; // must be larger than SHADA_MPACK_FREE_SPACE
char *alloc = xmalloc(initial_size);
return (PackerBuffer) {
.startptr = alloc,
.ptr = alloc,
.endptr = alloc + initial_size,
.packer_flush = flush_string_buffer,
};
}
static void flush_string_buffer(PackerBuffer *buffer)
{
size_t current_capacity = (size_t)(buffer->endptr - buffer->startptr);
size_t new_capacity = 2 * current_capacity;
size_t len = (size_t)(buffer->ptr - buffer->startptr);
buffer->startptr = xrealloc(buffer->startptr, new_capacity);
buffer->ptr = buffer->startptr + len;
buffer->endptr = buffer->startptr + new_capacity;
}
static String packer_take_string(PackerBuffer *buffer)
{
return (String){ .data = buffer->startptr, .size = (size_t)(buffer->ptr - buffer->startptr) };
}
/// Write registers ShaDa entries in given msgpack_sbuffer. /// Write registers ShaDa entries in given msgpack_sbuffer.
/// ///
/// @param[in] sbuf target msgpack_sbuffer to write to. /// @param[in] sbuf target msgpack_sbuffer to write to.
void shada_encode_regs(msgpack_sbuffer *const sbuf) String shada_encode_regs(void)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
WriteMergerState *const wms = xcalloc(1, sizeof(*wms)); WriteMergerState *const wms = xcalloc(1, sizeof(*wms));
shada_initialize_registers(wms, -1); shada_initialize_registers(wms, -1);
msgpack_packer packer; PackerBuffer packer = packer_string_buffer();
msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write);
for (size_t i = 0; i < ARRAY_SIZE(wms->registers); i++) { for (size_t i = 0; i < ARRAY_SIZE(wms->registers); i++) {
if (wms->registers[i].data.type == kSDItemRegister) { if (wms->registers[i].data.type == kSDItemRegister) {
if (kSDWriteFailed if (kSDWriteFailed
@@ -3972,52 +4006,53 @@ void shada_encode_regs(msgpack_sbuffer *const sbuf)
} }
} }
xfree(wms); xfree(wms);
return packer_take_string(&packer);
} }
/// Write jumplist ShaDa entries in given msgpack_sbuffer. /// Write jumplist ShaDa entries in given msgpack_sbuffer.
/// ///
/// @param[in] sbuf target msgpack_sbuffer to write to. /// @param[in] sbuf target msgpack_sbuffer to write to.
void shada_encode_jumps(msgpack_sbuffer *const sbuf) String shada_encode_jumps(void)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
Set(ptr_t) removable_bufs = SET_INIT; Set(ptr_t) removable_bufs = SET_INIT;
find_removable_bufs(&removable_bufs); find_removable_bufs(&removable_bufs);
PossiblyFreedShadaEntry jumps[JUMPLISTSIZE]; PossiblyFreedShadaEntry jumps[JUMPLISTSIZE];
size_t jumps_size = shada_init_jumps(jumps, &removable_bufs); size_t jumps_size = shada_init_jumps(jumps, &removable_bufs);
msgpack_packer packer; PackerBuffer packer = packer_string_buffer();
msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write);
for (size_t i = 0; i < jumps_size; i++) { for (size_t i = 0; i < jumps_size; i++) {
if (kSDWriteFailed == shada_pack_pfreed_entry(&packer, jumps[i], 0)) { if (kSDWriteFailed == shada_pack_pfreed_entry(&packer, jumps[i], 0)) {
abort(); abort();
} }
} }
return packer_take_string(&packer);
} }
/// Write buffer list ShaDa entry in given msgpack_sbuffer. /// Write buffer list ShaDa entry in given msgpack_sbuffer.
/// ///
/// @param[in] sbuf target msgpack_sbuffer to write to. /// @param[in] sbuf target msgpack_sbuffer to write to.
void shada_encode_buflist(msgpack_sbuffer *const sbuf) String shada_encode_buflist(void)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
Set(ptr_t) removable_bufs = SET_INIT; Set(ptr_t) removable_bufs = SET_INIT;
find_removable_bufs(&removable_bufs); find_removable_bufs(&removable_bufs);
ShadaEntry buflist_entry = shada_get_buflist(&removable_bufs); ShadaEntry buflist_entry = shada_get_buflist(&removable_bufs);
msgpack_packer packer;
msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write); PackerBuffer packer = packer_string_buffer();
if (kSDWriteFailed == shada_pack_entry(&packer, buflist_entry, 0)) { if (kSDWriteFailed == shada_pack_entry(&packer, buflist_entry, 0)) {
abort(); abort();
} }
xfree(buflist_entry.data.buffer_list.buffers); xfree(buflist_entry.data.buffer_list.buffers);
return packer_take_string(&packer);
} }
/// Write global variables ShaDa entries in given msgpack_sbuffer. /// Write global variables ShaDa entries in given msgpack_sbuffer.
/// ///
/// @param[in] sbuf target msgpack_sbuffer to write to. /// @param[in] sbuf target msgpack_sbuffer to write to.
void shada_encode_gvars(msgpack_sbuffer *const sbuf) String shada_encode_gvars(void)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
msgpack_packer packer; PackerBuffer packer = packer_string_buffer();
msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write);
const void *var_iter = NULL; const void *var_iter = NULL;
const Timestamp cur_timestamp = os_time(); const Timestamp cur_timestamp = os_time();
do { do {
@@ -4049,21 +4084,21 @@ void shada_encode_gvars(msgpack_sbuffer *const sbuf)
} }
tv_clear(&vartv); tv_clear(&vartv);
} while (var_iter != NULL); } while (var_iter != NULL);
return packer_take_string(&packer);
} }
/// Read ShaDa from msgpack_sbuffer. /// Read ShaDa from String.
/// ///
/// @param[in] file msgpack_sbuffer to read from. /// @param[in] string string to read from.
/// @param[in] flags Flags, see ShaDaReadFileFlags enum. /// @param[in] flags Flags, see ShaDaReadFileFlags enum.
void shada_read_sbuf(msgpack_sbuffer *const sbuf, const int flags) void shada_read_string(String string, const int flags)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
assert(sbuf != NULL); if (string.size == 0) {
if (sbuf->data == NULL) {
return; return;
} }
FileDescriptor sd_reader; FileDescriptor sd_reader;
file_open_buffer(&sd_reader, sbuf->data, sbuf->size); file_open_buffer(&sd_reader, string.data, string.size);
shada_read(&sd_reader, flags); shada_read(&sd_reader, flags);
close_file(&sd_reader); close_file(&sd_reader);
} }

View File

@@ -2,6 +2,8 @@
#include <msgpack.h> // IWYU pragma: keep #include <msgpack.h> // IWYU pragma: keep
#include "nvim/api/private/defs.h"
/// Flags for shada_read_file and children /// Flags for shada_read_file and children
typedef enum { typedef enum {
kShaDaWantInfo = 1, ///< Load non-mark information kShaDaWantInfo = 1, ///< Load non-mark information