void region_test_truncate() { header(); struct region region; region_create(®ion, &cache); void *ptr = region_alloc(®ion, 10); fail_unless(ptr); size_t used = region_used(®ion); region_alloc(®ion, 10000); region_alloc(®ion, 10000000); region_truncate(®ion, used); fail_unless(region_used(®ion) == used); region_free(®ion); footer(); }
void region_basic() { header(); struct region region; region_create(®ion, &cache); fail_unless(region_used(®ion) == 0); void *ptr = region_alloc(®ion, 10); fail_unless(ptr); fail_unless(region_used(®ion) == 10); ptr = region_alloc(®ion, 10000000); fail_unless(ptr); fail_unless(region_used(®ion) == 10000010); region_free(®ion); fail_unless(region_used(®ion) == 0); printf("name of a new region: %s.\n", region_name(®ion)); region_set_name(®ion, "region"); printf("set new region name: %s.\n", region_name(®ion)); region_set_name(®ion, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); printf("region name is truncated: %s.\n", region_name(®ion)); footer(); }
static int lbox_tuple_to_string(struct lua_State *L) { struct tuple *tuple = lua_checktuple(L, 1); size_t used = region_used(&fiber()->gc); char *res = tuple_to_yaml(tuple); if (res == NULL) { region_truncate(&fiber()->gc, used); return luaT_error(L); } lua_pushstring(L, res); region_truncate(&fiber()->gc, used); return 1; }
/** * Release all memory down to new_size; new_size has to be previously * obtained by calling region_used(). */ void region_truncate(struct region *region, size_t used) { ssize_t cut_size = region_used(region) - used; assert(cut_size >= 0); while (! rlist_empty(®ion->slabs.slabs)) { struct rslab *slab = rlist_first_entry(®ion->slabs.slabs, struct rslab, slab.next_in_list); if (slab->used > cut_size) { /* This is the last slab to trim. */ slab->used -= cut_size; cut_size = 0; break; } cut_size -= slab->used; /* Remove the entire slab. */ slab_list_del(®ion->slabs, &slab->slab, next_in_list); slab_put(region->cache, &slab->slab); } assert(cut_size == 0); region->slabs.stats.used = used; }
/** * Tuple transforming function. * * Remove the fields designated by 'offset' and 'len' from an tuple, * and replace them with the elements of supplied data fields, * if any. * * Function returns newly allocated tuple. * It does not change any parent tuple data. */ static int lbox_tuple_transform(struct lua_State *L) { struct tuple *tuple = lua_checktuple(L, 1); int argc = lua_gettop(L); if (argc < 3) luaL_error(L, "tuple.transform(): bad arguments"); lua_Integer offset = lua_tointeger(L, 2); /* Can be negative and can be > INT_MAX */ lua_Integer len = lua_tointeger(L, 3); lua_Integer field_count = box_tuple_field_count(tuple); /* validate offset and len */ if (offset == 0) { luaL_error(L, "tuple.transform(): offset is out of bound"); } else if (offset < 0) { if (-offset > field_count) luaL_error(L, "tuple.transform(): offset is out of bound"); offset += field_count + 1; } else if (offset > field_count) { offset = field_count + 1; } if (len < 0) luaL_error(L, "tuple.transform(): len is negative"); if (len > field_count + 1 - offset) len = field_count + 1 - offset; assert(offset + len <= field_count + 1); /* * Calculate the number of operations and length of UPDATE expression */ uint32_t op_cnt = 0; if (offset < field_count + 1 && len > 0) op_cnt++; if (argc > 3) op_cnt += argc - 3; if (op_cnt == 0) { /* tuple_update() does not accept an empty operation list. */ luaT_pushtuple(L, tuple); return 1; } struct ibuf *buf = tarantool_lua_ibuf; ibuf_reset(buf); struct mpstream stream; mpstream_init(&stream, buf, ibuf_reserve_cb, ibuf_alloc_cb, luamp_error, L); /* * Prepare UPDATE expression */ mpstream_encode_array(&stream, op_cnt); if (len > 0) { mpstream_encode_array(&stream, 3); mpstream_encode_str(&stream, "#"); mpstream_encode_uint(&stream, offset); mpstream_encode_uint(&stream, len); } for (int i = argc ; i > 3; i--) { mpstream_encode_array(&stream, 3); mpstream_encode_str(&stream, "!"); mpstream_encode_uint(&stream, offset); luamp_encode(L, luaL_msgpack_default, &stream, i); } mpstream_flush(&stream); uint32_t new_size = 0, bsize; const char *old_data = tuple_data_range(tuple, &bsize); struct region *region = &fiber()->gc; size_t used = region_used(region); struct tuple *new_tuple = NULL; /* * Can't use box_tuple_update() since transform must reset * the tuple format to default. The new tuple most likely * won't coerce into the original space format, so we have * to use the default one with no restrictions on field * count or types. */ const char *new_data = tuple_update_execute(region_aligned_alloc_cb, region, buf->buf, buf->buf + ibuf_used(buf), old_data, old_data + bsize, &new_size, 1, NULL); if (new_data != NULL) new_tuple = tuple_new(box_tuple_format_default(), new_data, new_data + new_size); region_truncate(region, used); if (new_tuple == NULL) luaT_error(L); luaT_pushtuple(L, new_tuple); ibuf_reset(buf); return 1; }