From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 88F69718B1; Tue, 19 Jan 2021 02:52:10 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 88F69718B1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1611013930; bh=vuhNr5P4dt3NR5mxVVU3FJpdDnWMdOOnte4P7spiQvM=; h=To:Date:In-Reply-To:References:In-Reply-To:References:Subject: List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help: List-Subscribe:From:Reply-To:Cc:From; b=jk3NbtAa2HjW5T+BVyo8B3Dy1Dh0ALnspRk27wpabi21g1mbUhIi3DyBxWU07hpy7 OQj0J6PHJdKn5Xi17GdRooayp1Ju+zAp7vCOkUFaUNeCYqDsOynZ3CAajZqCv+r2sA X37MI71huql2SgBzY2tNqRLJY0eEg2GbPbIT/25Q= Received: from smtp43.i.mail.ru (smtp43.i.mail.ru [94.100.177.103]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 3D28B85DEC for ; Tue, 19 Jan 2021 02:50:42 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 3D28B85DEC Received: by smtp43.i.mail.ru with esmtpa (envelope-from ) id 1l1eID-000553-4J; Tue, 19 Jan 2021 02:50:41 +0300 To: v.shpilevoy@tarantool.org, alyapunov@tarantool.org Date: Tue, 19 Jan 2021 02:50:32 +0300 Message-Id: <00e7a5de9f3abc8418976489cb46328ca1b08acc.1611013688.git.i.kosarev@tarantool.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: X-7564579A: B8F34718100C35BD X-77F55803: 4F1203BC0FB41BD9D0E79FBC973162CD9B382B274FF537389656BC690FF7BBE200894C459B0CD1B99D1EB34739C2031F87B316E84CCDB7325BDEB18AB7251EEF77626B0F71EFE3B5 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7C3AD35F3BF810D7EEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637B873F9B77FA959408638F802B75D45FF5571747095F342E8C7A0BC55FA0FE5FC76BE4C15C5329EC45DFD67612D302190819E39986D1FBD8B389733CBF5DBD5E913377AFFFEAFD269176DF2183F8FC7C07E7E81EEA8A9722B8941B15DA834481FCF19DD082D7633A0EF3E4896CB9E6436389733CBF5DBD5E9D5E8D9A59859A8B6D52CD31C43BF465FCC7F00164DA146DA6F5DAA56C3B73B237318B6A418E8EAB8D32BA5DBAC0009BE9E8FC8737B5C22496CE449B29A2285B576E601842F6C81A12EF20D2F80756B5F7E9C4E3C761E06A776E601842F6C81A127C277FBC8AE2E8B3E2C9532801809953AA81AA40904B5D9DBF02ECDB25306B2B25CBF701D1BE8734AD6D5ED66289B5278DA827A17800CE797E1AC076310AD6267F23339F89546C5A8DF7F3B2552694A6FED454B719173D6725E5C173C3A84C3FD340EA919DED65B35872C767BF85DA2F004C906525384306FED454B719173D6462275124DF8B9C9DF33B08B2BB81206574AF45C6390F7469DAA53EE0834AAEE X-C1DE0DAB: C20DE7B7AB408E4181F030C43753B8183A4AFAF3EA6BDC44C234C8B12C006B7A76BE4C15C5329EC45DFD67612D302190905595EC10825CE4B1881A6453793CE9C32612AADDFBE061C61BE10805914D3804EBA3D8E7E5B87ABF8C51168CD8EBDBC908CD1B87A134A2DC48ACC2A39D04F89CDFB48F4795C241BDAD6C7F3747799A X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D3403182E70AE6895E0446DE3822ACF3A6E1057A2B9CCDAAD7F34889F7333D95970D87A228BA510F7DF1D7E09C32AA3244C85AED3486AD7572729447D4A0CFDB5C0B4DF56057A86259F927AC6DF5659F194 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojbL9S8ysBdXjuG74y4HcDPckG3or/CNw4 X-Mailru-Sender: 06752BE58DD8CE37E6C4CE7F78F2F1FB42C1E127B6F17D2EDAB2DC77DEC50DC5E8285F0AB37D98A740CFBDB3DDA0AC31AAFFD2005305549D2F0B9811F39295BF38C65A79EEA694937402F9BA4338D657ED14614B50AE0675 X-Mras: Ok Subject: [Tarantool-patches] [PATCH 3/4] core: introduce tiny tuples X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Ilya Kosarev via Tarantool-patches Reply-To: Ilya Kosarev Cc: tarantool-patches@dev.tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" Tuple bsize was stored in 4 byte uint32_t field. Tuple data_offset was stored in 2 byte uint16_t field. Now the tuple contains flexible array at the end (0 or 4 bytes), allowing to put it in the same way. On the other hand, if it is possible, bsize and data_offset use 1 byte each. Such tuples are called tiny tuples. They only require 6 bytes instead of 10. As long as struct tuple is reassembled to achieve it and is now of variable size, inherited struct vy_stmt is also reworked now. It's members (except struct tuple itself) are not directly listed anymore. They were not used directly before and now they are not any more available to avoid accidental mistakes. lsn, type and flags of struct vy_stmt have to be accessed only using getters and setters now. Part of #5385 --- src/box/memtx_engine.c | 13 ++- src/box/tuple.c | 14 ++- src/box/tuple.h | 184 ++++++++++++++++++++++++++++---- src/box/vy_stmt.c | 19 ++-- src/box/vy_stmt.h | 38 +++++-- test/box/errinj.result | 18 ++-- test/box/upsert_errinj.result | 2 +- test/vinyl/cache.result | 6 +- test/vinyl/quota.result | 10 +- test/vinyl/quota_timeout.result | 8 +- test/vinyl/stat.result | 104 +++++++++--------- 11 files changed, 300 insertions(+), 116 deletions(-) diff --git a/src/box/memtx_engine.c b/src/box/memtx_engine.c index c37b35586..adb90e1c8 100644 --- a/src/box/memtx_engine.c +++ b/src/box/memtx_engine.c @@ -1219,6 +1219,8 @@ memtx_tuple_new(struct tuple_format *format, const char *data, const char *end) struct tuple *tuple = NULL; struct region *region = &fiber()->gc; size_t region_svp = region_used(region); + size_t tuple_len = end - data; + bool is_tiny = (tuple_len <= UINT8_MAX); struct field_map_builder builder; if (tuple_field_map_create(format, data, true, &builder) != 0) goto end; @@ -1228,7 +1230,12 @@ memtx_tuple_new(struct tuple_format *format, const char *data, const char *end) * tuple base, not from memtx_tuple, because the struct * tuple is not the first field of the memtx_tuple. */ - uint32_t data_offset = sizeof(struct tuple) + field_map_size; + is_tiny = (is_tiny && (sizeof(struct tuple) + + field_map_size <= MAX_TINY_DATA_OFFSET)); + uint32_t extra_size = field_map_size + + !is_tiny * sizeof(struct tuple_extra); + uint32_t data_offset = sizeof(struct tuple) + extra_size; + assert(!is_tiny || data_offset <= MAX_TINY_DATA_OFFSET); if (data_offset > INT16_MAX) { /** tuple data_offset can't be more than 15 bits */ diag_set(ClientError, ER_TUPLE_METADATA_IS_TOO_BIG, @@ -1236,8 +1243,7 @@ memtx_tuple_new(struct tuple_format *format, const char *data, const char *end) goto end; } - size_t tuple_len = end - data; - size_t total = sizeof(struct memtx_tuple) + field_map_size + tuple_len; + size_t total = sizeof(struct memtx_tuple) + tuple_len + extra_size; ERROR_INJECT(ERRINJ_TUPLE_ALLOC, { diag_set(OutOfMemory, total, "slab allocator", "memtx_tuple"); @@ -1263,6 +1269,7 @@ memtx_tuple_new(struct tuple_format *format, const char *data, const char *end) tuple = &memtx_tuple->base; tuple->refs = 0; memtx_tuple->version = memtx->snapshot_version; + tuple_set_tiny_bit(tuple, is_tiny); tuple_set_bsize(tuple, tuple_len); tuple->format_id = tuple_format_id(format); tuple_format_ref(format); diff --git a/src/box/tuple.c b/src/box/tuple.c index c73ad4566..db95d5872 100644 --- a/src/box/tuple.c +++ b/src/box/tuple.c @@ -79,11 +79,17 @@ runtime_tuple_new(struct tuple_format *format, const char *data, const char *end struct tuple *tuple = NULL; struct region *region = &fiber()->gc; size_t region_svp = region_used(region); + size_t data_len = end - data; + bool is_tiny = (data_len <= UINT8_MAX); struct field_map_builder builder; if (tuple_field_map_create(format, data, true, &builder) != 0) goto end; uint32_t field_map_size = field_map_build_size(&builder); - uint32_t data_offset = sizeof(struct tuple) + field_map_size; + is_tiny = (is_tiny && (sizeof(struct tuple) + + field_map_size <= MAX_TINY_DATA_OFFSET)); + uint32_t data_offset = sizeof(struct tuple) + field_map_size + + !is_tiny * sizeof(uint32_t); + assert(!is_tiny || data_offset <= MAX_TINY_DATA_OFFSET); if (data_offset > INT16_MAX) { /** tuple data_offset can't be more than 15 bits */ diag_set(ClientError, ER_TUPLE_METADATA_IS_TOO_BIG, @@ -91,9 +97,8 @@ runtime_tuple_new(struct tuple_format *format, const char *data, const char *end goto end; } - size_t data_len = end - data; - size_t total = sizeof(struct tuple) + field_map_size + data_len; - tuple = (struct tuple *) smalloc(&runtime_alloc, total); + size_t total = data_offset + data_len; + tuple = (struct tuple *)smalloc(&runtime_alloc, total); if (tuple == NULL) { diag_set(OutOfMemory, (unsigned) total, "malloc", "tuple"); @@ -101,6 +106,7 @@ runtime_tuple_new(struct tuple_format *format, const char *data, const char *end } tuple->refs = 0; + tuple_set_tiny_bit(tuple, is_tiny); tuple_set_bsize(tuple, data_len); tuple->format_id = tuple_format_id(format); tuple_format_ref(format); diff --git a/src/box/tuple.h b/src/box/tuple.h index aac054787..9eac52f01 100644 --- a/src/box/tuple.h +++ b/src/box/tuple.h @@ -296,6 +296,64 @@ box_tuple_validate(box_tuple_t *tuple, box_tuple_format_t *format); /** \endcond public */ +#define MAX_TINY_DATA_OFFSET 63 + +/** Part of struct tuple. */ +struct tiny_tuple_props { + /** + * Tuple is tiny in case it's bsize fits in 1 byte, + * it's data_offset fits in 6 bits and field map + * offsets fit into 1 byte each. + */ + bool is_tiny : 1; + /** + * The tuple (if it's found in index for example) could be invisible + * for current transactions. The flag means that the tuple must + * be clarified by the transaction engine. + */ + bool is_dirty : 1; + /** + * Offset to the MessagePack from the beginning of the + * tuple. 6 bits in case tuple is tiny. + */ + uint8_t data_offset : 6; + /** + * Length of the MessagePack data in raw part of the + * tuple. 8 bits in case tuple is tiny. + */ + uint8_t bsize; +}; + +/** Part of struct tuple. */ +struct tuple_props { + /** + * Tuple is tiny in case it's bsize fits in 1 byte, + * it's data_offset fits in 6 bits and field map + * offsets fit into 1 byte each. + */ + bool is_tiny : 1; + /** + * Offset to the MessagePack from the beginning of the + * tuple. 15 bits in case tuple is not tiny. + */ + uint16_t data_offset: 15; +}; + +/** Part of struct tuple. */ +struct PACKED tuple_extra { + /** + * The tuple (if it's found in index for example) could be invisible + * for current transactions. The flag means that the tuple must + * be clarified by the transaction engine. + */ + bool is_dirty : 1; + /** + * Length of the MessagePack data in raw part of the + * tuple. 31 bits in case tuple is not tiny. + */ + uint32_t bsize : 31; +}; + /** * An atom of Tarantool storage. Represents MsgPack Array. * Tuple has the following structure: @@ -323,20 +381,40 @@ struct PACKED tuple /** Format identifier. */ uint16_t format_id; /** - * Length of the MessagePack data in raw part of the - * tuple. - */ - uint32_t bsize; - /** - * Offset to the MessagePack from the begin of the tuple. + * Both structs in the following union contain is_tiny bit + * as the first field. It is guaranteed it will be the same + * for both of them in any case. Tuple is tiny in case it's + * bsize fits in 1 byte, it's data_offset fits in 6 bits and + * field map offsets fit into 1 byte each. In case it is tiny + * we will obtain data_offset, bsize and is_dirty flag from the + * struct tiny_tuple_props. Otherwise we will obtain data_offset + * from struct tuple_props, while bsize and is_dirty flag will be + * stored in struct tuple_extra (4 bytes at the end of the tuple). */ - uint16_t data_offset : 15; + union { + /** + * In case the tuple is tiny this struct is used to obtain + * data_offset (offset to the MessagePack from the beginning + * of the tuple), bsize (the length of the MessagePack data + * in the raw part of the tuple) and is_dirty flag (true if + * the tuple must be clarified by transaction engine). + */ + struct tiny_tuple_props tiny_props; + /** + * In case the tuple is not tiny this struct is used to obtain + * data_offset (offset to the MessagePack from the beginning of + * the tuple). + */ + struct tuple_props props; + }; /** - * The tuple (if it's found in index for example) could be invisible - * for current transactions. The flag means that the tuple must - * be clarified by transaction engine. + * In case the tuple is not tiny this struct contains is_dirty + * flag (true if the tuple must be clarified by transaction + * engine) and bsize (the length of the MessagePack data + * in the raw part of the tuple). + * If the tuple is tiny, this fields is 0 bytes. */ - bool is_dirty : 1; + struct tuple_extra extra[]; /** * Engine specific fields and offsets array concatenated * with MessagePack fields array. @@ -344,47 +422,117 @@ struct PACKED tuple */ }; +/** + * According to C standard sections 6.5.2.3-5 it is guaranteed + * if a union contains several structures that share a common + * initial sequence of members (bool is_tiny in this case), it is + * permitted to inspect the common initial part of any of them + * anywhere that a declaration of the complete type of the union + * is visible. Two structures share a common initial sequence if + * corresponding members have compatible types (and, for + * bit-fields, the same widths) for a sequence of one or more + * initial members. Thus we are guaranteed that is_tiny bit is + * same for both struct tiny_tuple_props and struct tuple_props + * and we can simply read or write any of them. + */ +static inline void +tuple_set_tiny_bit(struct tuple *tuple, bool is_tiny) +{ + assert(tuple != NULL); + tuple->props.is_tiny = is_tiny; +} + +static inline bool +tuple_is_tiny(struct tuple *tuple) +{ + assert(tuple != NULL); + return tuple->props.is_tiny; +} + +static inline void +tiny_tuple_set_dirty_bit(struct tuple *tuple, bool is_dirty) +{ + tuple->tiny_props.is_dirty = is_dirty; +} + +static inline void +basic_tuple_set_dirty_bit(struct tuple *tuple, bool is_dirty) +{ + tuple->extra->is_dirty = is_dirty; +} + static inline void tuple_set_dirty_bit(struct tuple *tuple, bool is_dirty) { assert(tuple != NULL); - tuple->is_dirty = is_dirty; + tuple->props.is_tiny ? tiny_tuple_set_dirty_bit(tuple, is_dirty) : + basic_tuple_set_dirty_bit(tuple, is_dirty); } static inline bool tuple_is_dirty(struct tuple *tuple) { assert(tuple != NULL); - return tuple->is_dirty; + return tuple->props.is_tiny ? tuple->tiny_props.is_dirty : + tuple->extra->is_dirty; +} + +static inline void +tiny_tuple_set_bsize(struct tuple *tuple, uint32_t bsize) +{ + assert(bsize <= UINT8_MAX); /* bsize has to fit in UINT8_MAX */ + tuple->tiny_props.bsize = bsize; +} + +static inline void +basic_tuple_set_bsize(struct tuple *tuple, uint32_t bsize) +{ + assert(bsize <= INT32_MAX); /* bsize has to fit in INT32_MAX */ + tuple->extra->bsize = bsize; } static inline void tuple_set_bsize(struct tuple *tuple, uint32_t bsize) { assert(tuple != NULL); - assert(bsize <= UINT32_MAX); /* bsize is UINT32_MAX */ - tuple->bsize = bsize; + tuple->props.is_tiny ? tiny_tuple_set_bsize(tuple, bsize) : + basic_tuple_set_bsize(tuple, bsize); } static inline uint32_t tuple_bsize(struct tuple *tuple) { assert(tuple != NULL); - return tuple->bsize; + return tuple->props.is_tiny ? tuple->tiny_props.bsize : + tuple->extra->bsize; +} + +static inline void +tiny_tuple_set_data_offset(struct tuple *tuple, uint8_t data_offset) +{ + tuple->tiny_props.data_offset = data_offset; +} + +static inline void +basic_tuple_set_data_offset(struct tuple *tuple, uint16_t data_offset) +{ + tuple->props.data_offset = data_offset; } static inline void tuple_set_data_offset(struct tuple *tuple, uint16_t data_offset) { assert(tuple != NULL); - tuple->data_offset = data_offset; + tuple->props.is_tiny ? tiny_tuple_set_data_offset(tuple, data_offset) : + basic_tuple_set_data_offset(tuple, data_offset); } static inline uint16_t tuple_data_offset(struct tuple *tuple) { assert(tuple != NULL); - return tuple->data_offset; + return tuple->props.is_tiny ? tuple->tiny_props.data_offset : + tuple->props.data_offset; } /** Size of the tuple including size of struct tuple. */ diff --git a/src/box/vy_stmt.c b/src/box/vy_stmt.c index accafc654..97bc1e408 100644 --- a/src/box/vy_stmt.c +++ b/src/box/vy_stmt.c @@ -158,7 +158,8 @@ vy_stmt_format_new(struct vy_stmt_env *env, struct key_def *const *keys, static struct tuple * vy_stmt_alloc(struct tuple_format *format, uint32_t data_offset, uint32_t bsize) { - assert(data_offset >= sizeof(struct vy_stmt) + format->field_map_size); + assert(data_offset >= size_of_struct_vy_stmt() + + format->field_map_size); if (data_offset > INT16_MAX) { /** tuple data_offset can't be more than 15 bits */ @@ -196,6 +197,7 @@ vy_stmt_alloc(struct tuple_format *format, uint32_t data_offset, uint32_t bsize) tuple->format_id = tuple_format_id(format); if (cord_is_main()) tuple_format_ref(format); + tuple_set_tiny_bit(tuple, false); tuple_set_bsize(tuple, bsize); tuple_set_data_offset(tuple, data_offset); tuple_set_dirty_bit(tuple, false); @@ -280,11 +282,12 @@ vy_key_new(struct tuple_format *format, const char *key, uint32_t part_count) /* Allocate stmt */ uint32_t key_size = key_end - key; uint32_t bsize = mp_sizeof_array(part_count) + key_size; - struct tuple *stmt = vy_stmt_alloc(format, sizeof(struct vy_stmt), bsize); + struct tuple *stmt = vy_stmt_alloc(format, size_of_struct_vy_stmt(), + bsize); if (stmt == NULL) return NULL; /* Copy MsgPack data */ - char *raw = (char *) stmt + sizeof(struct vy_stmt); + char *raw = (char *)stmt + size_of_struct_vy_stmt(); char *data = mp_encode_array(raw, part_count); memcpy(data, key, key_size); assert(data + key_size == raw + bsize); @@ -351,7 +354,7 @@ vy_stmt_new_with_ops(struct tuple_format *format, const char *tuple_begin, */ size_t mpsize = (tuple_end - tuple_begin); size_t bsize = mpsize + ops_size; - stmt = vy_stmt_alloc(format, sizeof(struct vy_stmt) + + stmt = vy_stmt_alloc(format, size_of_struct_vy_stmt() + field_map_size, bsize); if (stmt == NULL) goto end; @@ -422,10 +425,10 @@ vy_stmt_replace_from_upsert(struct tuple *upsert) if (replace == NULL) return NULL; /* Copy both data and field_map. */ - char *dst = (char *)replace + sizeof(struct vy_stmt); - char *src = (char *)upsert + sizeof(struct vy_stmt); + char *dst = (char *)replace + size_of_struct_vy_stmt(); + char *src = (char *)upsert + size_of_struct_vy_stmt(); memcpy(dst, src, tuple_data_offset(upsert) + - bsize - sizeof(struct vy_stmt)); + bsize - size_of_struct_vy_stmt()); vy_stmt_set_type(replace, IPROTO_REPLACE); vy_stmt_set_lsn(replace, vy_stmt_lsn(upsert)); return replace; @@ -502,7 +505,7 @@ vy_stmt_new_surrogate_delete_raw(struct tuple_format *format, assert(pos <= data + src_size); uint32_t bsize = pos - data; uint32_t field_map_size = field_map_build_size(&builder); - stmt = vy_stmt_alloc(format, sizeof(struct vy_stmt) + field_map_size, + stmt = vy_stmt_alloc(format, size_of_struct_vy_stmt() + field_map_size, bsize); if (stmt == NULL) goto out; diff --git a/src/box/vy_stmt.h b/src/box/vy_stmt.h index 69f46d67c..50b196fc3 100644 --- a/src/box/vy_stmt.h +++ b/src/box/vy_stmt.h @@ -171,9 +171,15 @@ enum { */ struct vy_stmt { struct tuple base; - int64_t lsn; - uint8_t type; /* IPROTO_INSERT/REPLACE/UPSERT/DELETE */ - uint8_t flags; + /** + * Following fields are stored without direct naming + * due to the fact that struct tuple has variable size. + * It also allows us to store them in compact way. + * Use getters and setters to access them. + * int64_t lsn; + * uint8_t type; IPROTO_INSERT/REPLACE/UPSERT/DELETE + * uint8_t flags; + */ /** * Offsets array concatenated with MessagePack fields * array. @@ -181,46 +187,60 @@ struct vy_stmt { */ }; +static inline size_t +size_of_basic_tuple(void) +{ + return sizeof(struct tuple) + sizeof(struct tuple_extra); +} + +static inline size_t +size_of_struct_vy_stmt(void) +{ + return size_of_basic_tuple() + sizeof(int64_t) + 2 * sizeof(uint8_t); +} + /** Get LSN of the vinyl statement. */ static inline int64_t vy_stmt_lsn(struct tuple *stmt) { - return ((struct vy_stmt *) stmt)->lsn; + return load_u64((void *)stmt + size_of_basic_tuple()); } /** Set LSN of the vinyl statement. */ static inline void vy_stmt_set_lsn(struct tuple *stmt, int64_t lsn) { - ((struct vy_stmt *) stmt)->lsn = lsn; + store_u64((void *)stmt + size_of_basic_tuple(), lsn); } /** Get type of the vinyl statement. */ static inline enum iproto_type vy_stmt_type(struct tuple *stmt) { - return (enum iproto_type)((struct vy_stmt *) stmt)->type; + return load_u8((void *)stmt + size_of_basic_tuple() + sizeof(int64_t)); } /** Set type of the vinyl statement. */ static inline void vy_stmt_set_type(struct tuple *stmt, enum iproto_type type) { - ((struct vy_stmt *) stmt)->type = type; + store_u8((void *)stmt + size_of_basic_tuple() + sizeof(int64_t), type); } /** Get flags of the vinyl statement. */ static inline uint8_t vy_stmt_flags(struct tuple *stmt) { - return ((struct vy_stmt *)stmt)->flags; + return load_u8((void *)stmt + size_of_basic_tuple() + sizeof(int64_t) + + sizeof(uint8_t)); } /** Set flags of the vinyl statement. */ static inline void vy_stmt_set_flags(struct tuple *stmt, uint8_t flags) { - ((struct vy_stmt *)stmt)->flags = flags; + store_u8((void *)stmt + size_of_basic_tuple() + + sizeof(int64_t) + sizeof(uint8_t), flags); } /** diff --git a/test/box/errinj.result b/test/box/errinj.result index b8c2476c3..0b1990e03 100644 --- a/test/box/errinj.result +++ b/test/box/errinj.result @@ -455,7 +455,7 @@ errinj.set("ERRINJ_TUPLE_ALLOC", true) ... s:auto_increment{} --- -- error: Failed to allocate 16 bytes in slab allocator for memtx_tuple +- error: Failed to allocate 12 bytes in slab allocator for memtx_tuple ... s:select{} --- @@ -463,7 +463,7 @@ s:select{} ... s:auto_increment{} --- -- error: Failed to allocate 16 bytes in slab allocator for memtx_tuple +- error: Failed to allocate 12 bytes in slab allocator for memtx_tuple ... s:select{} --- @@ -471,7 +471,7 @@ s:select{} ... s:auto_increment{} --- -- error: Failed to allocate 16 bytes in slab allocator for memtx_tuple +- error: Failed to allocate 12 bytes in slab allocator for memtx_tuple ... s:select{} --- @@ -485,7 +485,7 @@ box.begin() s:insert{1} box.commit(); --- -- error: Failed to allocate 16 bytes in slab allocator for memtx_tuple +- error: Failed to allocate 12 bytes in slab allocator for memtx_tuple ... box.rollback(); --- @@ -499,7 +499,7 @@ box.begin() s:insert{2} box.commit(); --- -- error: Failed to allocate 16 bytes in slab allocator for memtx_tuple +- error: Failed to allocate 12 bytes in slab allocator for memtx_tuple ... s:select{}; --- @@ -513,7 +513,7 @@ box.begin() s:insert{2} box.commit(); --- -- error: Failed to allocate 16 bytes in slab allocator for memtx_tuple +- error: Failed to allocate 12 bytes in slab allocator for memtx_tuple ... s:select{}; --- @@ -532,7 +532,7 @@ box.begin() s:insert{2} box.commit(); --- -- error: Failed to allocate 16 bytes in slab allocator for memtx_tuple +- error: Failed to allocate 12 bytes in slab allocator for memtx_tuple ... errinj.set("ERRINJ_TUPLE_ALLOC", false); --- @@ -794,7 +794,7 @@ errinj.set("ERRINJ_TUPLE_ALLOC", true) ... s:replace{1, "test"} --- -- error: Failed to allocate 21 bytes in slab allocator for memtx_tuple +- error: Failed to allocate 17 bytes in slab allocator for memtx_tuple ... s:bsize() --- @@ -806,7 +806,7 @@ utils.space_bsize(s) ... s:update({1}, {{'=', 3, '!'}}) --- -- error: Failed to allocate 20 bytes in slab allocator for memtx_tuple +- error: Failed to allocate 16 bytes in slab allocator for memtx_tuple ... s:bsize() --- diff --git a/test/box/upsert_errinj.result b/test/box/upsert_errinj.result index ed52e2855..3aca98191 100644 --- a/test/box/upsert_errinj.result +++ b/test/box/upsert_errinj.result @@ -19,7 +19,7 @@ errinj.set("ERRINJ_TUPLE_ALLOC", true) ... s:upsert({111, '111', 222, '222'}, {{'!', 5, '!'}}) --- -- error: Failed to allocate 26 bytes in slab allocator for memtx_tuple +- error: Failed to allocate 22 bytes in slab allocator for memtx_tuple ... errinj.set("ERRINJ_TUPLE_ALLOC", false) --- diff --git a/test/vinyl/cache.result b/test/vinyl/cache.result index 49d2bcc7a..4c9e0a96d 100644 --- a/test/vinyl/cache.result +++ b/test/vinyl/cache.result @@ -1033,14 +1033,14 @@ for i = 1, 100 do s:get{i} end ... box.stat.vinyl().memory.tuple_cache --- -- 108500 +- 107300 ... box.cfg{vinyl_cache = 50 * 1000} --- ... box.stat.vinyl().memory.tuple_cache --- -- 49910 +- 49358 ... box.cfg{vinyl_cache = 0} --- @@ -1116,7 +1116,7 @@ s.index.i2:count() ... box.stat.vinyl().memory.tuple_cache -- should be about 200 KB --- -- 219200 +- 218000 ... s:drop() --- diff --git a/test/vinyl/quota.result b/test/vinyl/quota.result index 70e81453d..0d0cded1a 100644 --- a/test/vinyl/quota.result +++ b/test/vinyl/quota.result @@ -36,7 +36,7 @@ space:insert({1, 1}) ... box.stat.vinyl().memory.level0 --- -- 98344 +- 98336 ... space:insert({1, 1}) --- @@ -44,7 +44,7 @@ space:insert({1, 1}) ... box.stat.vinyl().memory.level0 --- -- 98344 +- 98336 ... space:update({1}, {{'!', 1, 100}}) -- try to modify the primary key --- @@ -52,7 +52,7 @@ space:update({1}, {{'!', 1, 100}}) -- try to modify the primary key ... box.stat.vinyl().memory.level0 --- -- 98344 +- 98336 ... space:insert({2, 2}) --- @@ -68,7 +68,7 @@ space:insert({4, 4}) ... box.stat.vinyl().memory.level0 --- -- 98463 +- 98417 ... box.snapshot() --- @@ -94,7 +94,7 @@ _ = space:replace{1, 1, string.rep('a', 1024 * 1024 * 5)} ... box.stat.vinyl().memory.level0 --- -- 5292080 +- 5292064 ... space:drop() --- diff --git a/test/vinyl/quota_timeout.result b/test/vinyl/quota_timeout.result index 31ca23670..0690823cf 100644 --- a/test/vinyl/quota_timeout.result +++ b/test/vinyl/quota_timeout.result @@ -49,7 +49,7 @@ s:count() ... box.stat.vinyl().memory.level0 --- -- 748248 +- 748232 ... -- Since the following operation requires more memory than configured -- and dump is disabled, it should fail with ER_VY_QUOTA_TIMEOUT. @@ -63,7 +63,7 @@ s:count() ... box.stat.vinyl().memory.level0 --- -- 748248 +- 748232 ... -- -- Check that increasing box.cfg.vinyl_memory wakes up fibers @@ -135,7 +135,7 @@ test_run:cmd("push filter '[0-9.]+ sec' to ' sec'") ... test_run:grep_log('test', 'waited for .* quota for too long.*') --- -- 'waited for 1048615 bytes of vinyl memory quota for too long: sec' +- 'waited for 1048603 bytes of vinyl memory quota for too long: sec' ... test_run:cmd("clear filter") --- @@ -167,7 +167,7 @@ pad = string.rep('x', box.cfg.vinyl_memory) ... _ = s:auto_increment{pad} --- -- error: Failed to allocate 1572903 bytes in lsregion for vinyl transaction +- error: Failed to allocate 1572891 bytes in lsregion for vinyl transaction ... s:drop() --- diff --git a/test/vinyl/stat.result b/test/vinyl/stat.result index a895528b9..18b186633 100644 --- a/test/vinyl/stat.result +++ b/test/vinyl/stat.result @@ -301,7 +301,7 @@ stat_diff(istat(), st) --- - put: rows: 25 - bytes: 26525 + bytes: 26225 rows: 25 run_avg: 1 run_count: 1 @@ -318,7 +318,7 @@ stat_diff(istat(), st) dump: input: rows: 25 - bytes: 26525 + bytes: 26225 count: 1 output: bytes: 26049 @@ -350,7 +350,7 @@ stat_diff(istat(), st) --- - put: rows: 50 - bytes: 53050 + bytes: 52450 bytes: 26042 disk: last_level: @@ -364,7 +364,7 @@ stat_diff(istat(), st) dump: input: rows: 50 - bytes: 53050 + bytes: 52450 count: 1 output: bytes: 52091 @@ -402,11 +402,11 @@ stat_diff(istat(), st) - cache: index_size: 49152 rows: 1 - bytes: 1061 + bytes: 1049 lookup: 1 put: rows: 1 - bytes: 1061 + bytes: 1049 lookup: 1 disk: iterator: @@ -418,13 +418,13 @@ stat_diff(istat(), st) lookup: 1 get: rows: 1 - bytes: 1061 + bytes: 1049 memory: iterator: lookup: 1 get: rows: 1 - bytes: 1061 + bytes: 1049 ... -- point lookup from cache st = istat() @@ -440,14 +440,14 @@ stat_diff(istat(), st) lookup: 1 put: rows: 1 - bytes: 1061 + bytes: 1049 get: rows: 1 - bytes: 1061 + bytes: 1049 lookup: 1 get: rows: 1 - bytes: 1061 + bytes: 1049 ... -- put in memory + cache invalidate st = istat() @@ -461,18 +461,18 @@ stat_diff(istat(), st) - cache: invalidate: rows: 1 - bytes: 1061 + bytes: 1049 rows: -1 - bytes: -1061 + bytes: -1049 rows: 1 memory: index_size: 49152 - bytes: 1061 + bytes: 1049 rows: 1 put: rows: 1 - bytes: 1061 - bytes: 1061 + bytes: 1049 + bytes: 1049 ... -- point lookup from memory st = istat() @@ -485,22 +485,22 @@ s:get(1) ~= nil stat_diff(istat(), st) --- - cache: - bytes: 1061 + bytes: 1049 lookup: 1 rows: 1 put: rows: 1 - bytes: 1061 + bytes: 1049 memory: iterator: lookup: 1 get: rows: 1 - bytes: 1061 + bytes: 1049 lookup: 1 get: rows: 1 - bytes: 1061 + bytes: 1049 ... -- put in txw + point lookup from txw st = istat() @@ -520,16 +520,16 @@ stat_diff(istat(), st) --- - txw: rows: 1 - bytes: 1061 + bytes: 1049 iterator: lookup: 1 get: rows: 1 - bytes: 1061 + bytes: 1049 lookup: 1 get: rows: 1 - bytes: 1061 + bytes: 1049 ... box.rollback() --- @@ -586,15 +586,15 @@ for i = 1, 100 do s:get(i) end ... stat_diff(istat(), st, 'cache') --- -- rows: 14 - bytes: 14854 +- rows: 15 + bytes: 15735 evict: - rows: 86 - bytes: 91246 + rows: 85 + bytes: 89165 lookup: 100 put: rows: 100 - bytes: 106100 + bytes: 104900 ... -- range split for i = 1, 100 do put(i) end @@ -649,15 +649,15 @@ st = istat() stat_diff(istat(), st) --- - cache: - rows: 13 - bytes: 13793 + rows: 14 + bytes: 14686 evict: - rows: 37 - bytes: 39257 + rows: 36 + bytes: 37764 lookup: 1 put: rows: 51 - bytes: 54111 + bytes: 53499 disk: iterator: read: @@ -668,23 +668,23 @@ stat_diff(istat(), st) lookup: 2 get: rows: 100 - bytes: 106100 + bytes: 104900 txw: iterator: lookup: 1 get: rows: 50 - bytes: 53050 + bytes: 52450 memory: iterator: lookup: 1 get: rows: 100 - bytes: 106100 + bytes: 104900 lookup: 1 get: rows: 100 - bytes: 106100 + bytes: 104900 ... box.rollback() --- @@ -717,17 +717,17 @@ stat_diff(istat(), st) lookup: 1 put: rows: 5 - bytes: 5305 + bytes: 5245 get: rows: 5 - bytes: 5305 + bytes: 5245 txw: iterator: lookup: 1 lookup: 1 get: rows: 5 - bytes: 5305 + bytes: 5245 ... box.rollback() --- @@ -761,7 +761,7 @@ put(1) ... stat_diff(gstat(), st, 'memory.level0') --- -- 1064 +- 1049 ... -- use cache st = gstat() @@ -772,7 +772,7 @@ _ = s:get(1) ... stat_diff(gstat(), st, 'memory.tuple_cache') --- -- 1109 +- 1097 ... s:delete(1) --- @@ -1011,7 +1011,7 @@ istat() rows: 0 bytes: 0 index_size: 49152 - rows: 13 + rows: 14 evict: rows: 0 bytes: 0 @@ -1019,7 +1019,7 @@ istat() rows: 0 bytes: 0 lookup: 0 - bytes: 13793 + bytes: 14686 get: rows: 0 bytes: 0 @@ -1088,7 +1088,7 @@ istat() upsert: squashed: 0 applied: 0 - bytes: 317731 + bytes: 315259 put: rows: 0 bytes: 0 @@ -1105,7 +1105,7 @@ istat() rows: 0 bytes: 0 memory: - bytes: 213431 + bytes: 210959 index_size: 49152 rows: 206 iterator: @@ -1128,9 +1128,9 @@ gstat() gap_locks: 0 read_views: 0 memory: - tuple_cache: 14417 + tuple_cache: 15358 tx: 0 - level0: 263210 + level0: 260118 page_index: 1250 bloom_filter: 140 disk: @@ -1173,7 +1173,7 @@ box.snapshot() ... stat_diff(gstat(), st, 'scheduler') --- -- dump_input: 104200 +- dump_input: 103000 dump_output: 103592 tasks_completed: 2 dump_count: 1 @@ -1190,7 +1190,7 @@ box.snapshot() ... stat_diff(gstat(), st, 'scheduler') --- -- dump_input: 10420 +- dump_input: 10300 dump_output: 10411 tasks_completed: 2 dump_count: 1 @@ -1272,7 +1272,7 @@ st2 = i2:stat() ... s:bsize() --- -- 53300 +- 52700 ... i1:len(), i2:len() --- @@ -1397,7 +1397,7 @@ st2 = i2:stat() ... s:bsize() --- -- 107199 +- 105999 ... i1:len(), i2:len() --- -- 2.17.1