diff --git a/src/lib/core/prbuf.c b/src/lib/core/prbuf.c index 6e85b3a5d017546f017dafc488b07c6439d00339..dbd5d7a7f15c86bf76e363fd4ce6f53303ce28b2 100644 --- a/src/lib/core/prbuf.c +++ b/src/lib/core/prbuf.c @@ -73,7 +73,7 @@ static const size_t record_size_overhead = sizeof(struct prbuf_record); static uint32_t prbuf_record_alloc_size(size_t size) { - return size + offsetof(struct prbuf_record, data); + return size + record_size_overhead; } /** Returns pointer to the next byte after end of given buffer. */ @@ -138,10 +138,16 @@ prbuf_size(struct prbuf *buf) return buf->header->size - sizeof(struct prbuf_header); } +size_t +prbuf_max_record_size(struct prbuf *buf) +{ + return prbuf_size(buf) - record_size_overhead; +} + void prbuf_create(struct prbuf *buf, void *mem, size_t size) { - assert(size > sizeof(struct prbuf_header)); + assert(size > (sizeof(struct prbuf_header) + record_size_overhead)); #ifndef NDEBUG memset(mem, '#', size); #endif diff --git a/src/lib/core/prbuf.h b/src/lib/core/prbuf.h index 5fda3a2bf2fad7109abf769bfcf93e5d6e2609d4..dcc740371739e3333b6d232d8b7b3584cda0ae23 100644 --- a/src/lib/core/prbuf.h +++ b/src/lib/core/prbuf.h @@ -4,7 +4,6 @@ * * Copyright 2010-2022, Tarantool AUTHORS, please see AUTHORS file. */ -#include <stdbool.h> #include <stddef.h> /** Data entry of prbuf. Public analogue of struct prbuf_record. */ @@ -59,6 +58,12 @@ prbuf_create(struct prbuf *buf, void *mem, size_t size); int prbuf_open(struct prbuf *buf, void *mem); +/** + * Maximum record size we can store in the buffer. + */ +size_t +prbuf_max_record_size(struct prbuf *buf); + /** * Returns pointer to memory chunk sizeof @a size. * Note that without further prbuf_commit() call this function may return diff --git a/test/unit/prbuf.c b/test/unit/prbuf.c index 32ddd357cebad57c349fbf0c0970a57b59bc299b..3857c12535f09dc33e99777cc4e6e183f1fb14ab 100644 --- a/test/unit/prbuf.c +++ b/test/unit/prbuf.c @@ -328,6 +328,59 @@ test_buffer_prepared_large(void) footer(); } +/** + * Check: + * - we can alloc record of prbuf_max_record_size + * - we can't alloc larger buffer + * - record of max size is actually usable + */ +static void +test_max_record_size(void) +{ + header(); + + struct prbuf buf; + char mem[73]; + char payload[73]; + + prbuf_create(&buf, mem, sizeof(mem)); + int max_size = prbuf_max_record_size(&buf); + + int i; + for (i = 0; i < max_size; i++) + payload[i] = (char)i; + + char *p = prbuf_prepare(&buf, max_size); + ok(p != NULL, "not NULL is expected"); + memcpy(p, payload, max_size); + prbuf_commit(&buf); + + struct prbuf rbuf; + struct prbuf_iterator iter; + struct prbuf_entry entry; + + if (prbuf_open(&rbuf, mem) != 0) + fail("prbuf_open", "not 0"); + prbuf_iterator_create(&rbuf, &iter); + + int rc = prbuf_iterator_next(&iter, &entry); + ok(rc == 0, "rc is %d", rc); + ok(entry.size == (size_t)max_size, + "expected %d got %zd", max_size, entry.size); + if (entry.size != (size_t)max_size) + fail("entry size", "incorrect"); + ok(memcmp(entry.ptr, payload, max_size) == 0, + "0 is expected"); + + rc = prbuf_iterator_next(&iter, &entry); + ok(rc == -1, "rc is %d", rc); + + p = prbuf_prepare(&buf, max_size + 1); + ok(p == NULL, "NULL is expected"); + + footer(); +} + /** * There are three possible configurations of test: * 1. The size of buffer; @@ -337,7 +390,7 @@ test_buffer_prepared_large(void) int main(void) { - plan(39); + plan(45); payload_large_init(); test_buffer_foreach_size(); test_buffer_bad_version(); @@ -347,5 +400,6 @@ main(void) test_buffer_empty(); test_buffer_prepared(); test_buffer_prepared_large(); + test_max_record_size(); return check_plan(); }