#include #include #include #include #include #include "../test_api/test_api.hpp" int primary[11] = {0,1,2,3,4,5,6,7,8,9,10}; int secondary[11] = {7,0,1,3,6,9,10,2,4,5,8}; int tertiary[11] = {0,10,1,2,4,3,5,6,7,8,9}; int primary_lb[11] = {0,0,0,3,3,3,6,7,7,9,9}; int secondary_lb[11] = {0,0,10,0,10,10,0,7,8,0,10}; int tertiary_lb[11] = {0,1,2,3,2,5,6,7,8,9,0}; int primary_ub[11] = {3,3,3,6,6,6,7,9,9,-1,-1}; int secondary_ub[11] = {10,10,8,10,8,8,10,0,-1,10,8}; int tertiary_ub[11] = {1,2,3,5,3,6,7,8,9,-1,1}; #pragma pack(push, 1) struct test_model { account_name name; unsigned char age; uint64_t phone; }; struct test_model_v2 : test_model { test_model_v2() : new_field(0) {} uint64_t new_field; }; struct test_model_v3 : test_model_v2 { uint64_t another_field; }; struct TestModel128x2 { uint128_t number; uint128_t price; uint64_t extra; uint64_t table_name; }; struct TestModel128x2_V2 : TestModel128x2 { uint64_t new_field; }; struct TestModel3xi64 { uint64_t a; uint64_t b; uint64_t c; uint64_t table; }; struct TestModel3xi64_V2 : TestModel3xi64 { uint64_t new_field; }; #pragma pack(pop) #define STRLEN(s) my_strlen(s) extern "C" { void my_memset(void *vptr, unsigned char val, unsigned int size) { char *ptr = (char *)vptr; while(size--) { *(ptr++)=val; } } uint32_t my_strlen(const char *str) { uint32_t len = 0; while(str[len]) ++len; return len; } bool my_memcmp(void *s1, void *s2, uint32_t n) { unsigned char *c1 = (unsigned char*)s1; unsigned char *c2 = (unsigned char*)s2; for (uint32_t i = 0; i < n; i++) { if (c1[i] != c2[i]) { return false; } } return true; } } void test_db::key_str_table() { const char* keys[] = { "alice", "bob", "carol", "dave" }; const char* vals[] = { "data1", "data2", "data3", "data4" }; const char* atr[] = { "atr", "atr", "atr", "atr" }; const char* ztr[] = { "ztr", "ztr", "ztr", "ztr" }; eosio::var_table StringTableAtr; eosio::var_table StringTableZtr; eosio::var_table StringTableStr; uint32_t res = 0; // fill some data in contiguous tables for( int ii = 0; ii < 4; ++ii ) { res = StringTableAtr.store( (char*)keys[ii], STRLEN(keys[ii]), (char*)atr[ii], STRLEN(atr[ii]) ); assert( res != 0, "atr" ); res = StringTableZtr.store( (char*)keys[ii], STRLEN(keys[ii]), (char*)ztr[ii], STRLEN(ztr[ii]) ); assert(res != 0, "ztr" ); } char tmp[64]; res = StringTableStr.store ((char *)keys[0], STRLEN(keys[0]), (char *)vals[0], STRLEN(vals[0])); assert(res != 0, "store alice" ); res = StringTableStr.store((char *)keys[1], STRLEN(keys[1]), (char *)vals[1], STRLEN(vals[1]) ); assert(res != 0, "store bob" ); res = StringTableStr.store((char *)keys[2], STRLEN(keys[2]), (char *)vals[2], STRLEN(vals[2]) ); assert(res != 0, "store carol" ); res = StringTableStr.store((char *)keys[3], STRLEN(keys[3]), (char *)vals[3], STRLEN(vals[3]) ); assert(res != 0, "store dave" ); res = StringTableStr.load((char *)keys[0], STRLEN(keys[0]), tmp, 64); assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "load alice"); res = StringTableStr.load((char *)keys[1], STRLEN(keys[1]), tmp, 64); assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "load bob"); res = StringTableStr.load((char *)keys[2], STRLEN(keys[2]), tmp, 64); assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "load carol"); res = StringTableStr.load((char *)keys[3], STRLEN(keys[3]), tmp, 64); assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "load dave"); res = StringTableStr.previous((char *)keys[3], STRLEN(keys[3]), tmp, 64); assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "back carol"); res = StringTableStr.previous((char *)keys[2], STRLEN(keys[2]), tmp, 64); assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "back dave"); res = StringTableStr.previous((char *)keys[1], STRLEN(keys[1]), tmp, 64); assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "back alice"); res = StringTableStr.previous((char *)keys[0], STRLEN(keys[0]), tmp, 64); assert(res == -1, "no prev"); res = StringTableStr.next((char *)keys[0], STRLEN(keys[0]), tmp, 64); assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "next bob"); res = StringTableStr.next((char *)keys[1], STRLEN(keys[1]), tmp, 64); assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "next carol"); res = StringTableStr.next((char *)keys[2], STRLEN(keys[2]), tmp, 64); assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "next dave"); res = StringTableStr.next((char *)keys[3], STRLEN(keys[3]), tmp, 64); assert(res == -1, "no next"); res = StringTableStr.next((char *)keys[0], STRLEN(keys[0]), tmp, 0); assert(res == 0, "next 0"); res = StringTableStr.front((char*)keys[0], STRLEN(keys[0]), tmp, 64); assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "front alice"); res = StringTableStr.back((char*)keys[0], STRLEN(keys[0]), tmp, 64); assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "back dave"); res = StringTableStr.lower_bound((char *)keys[0], STRLEN(keys[0]), tmp, 64); assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "lowerbound alice"); res = StringTableStr.upper_bound((char *)keys[0], STRLEN(keys[0]), tmp, 64); assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "upperbound bob"); res = StringTableStr.lower_bound((char *)keys[3], STRLEN(keys[3]), tmp, 64); assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "upperbound dave"); res = StringTableStr.upper_bound((char *)keys[3], STRLEN(keys[3]), tmp, 64); assert(res == -1, "no upper_bound"); } void test_db::key_str_general() { const char* keys[] = { "alice", "bob", "carol", "dave" }; const char* vals[] = { "data1", "data2", "data3", "data4" }; const char* atr[] = { "atr", "atr", "atr", "atr" }; const char* ztr[] = { "ztr", "ztr", "ztr", "ztr" }; uint32_t res=0; //fill some data in contiguous tables for(int i=0; i < 4; ++i) { res = store_str(current_receiver(), N(atr), (char *)keys[i], STRLEN(keys[i]), (char *)atr[i], STRLEN(atr[i]) ); assert(res != 0, "atr" ); res = store_str(current_receiver(), N(ztr), (char *)keys[i], STRLEN(keys[i]), (char *)ztr[i], STRLEN(ztr[i]) ); assert(res != 0, "ztr" ); } char tmp[64]; res = store_str(current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), (char *)vals[0], STRLEN(vals[0]) ); assert(res != 0, "store alice" ); res = store_str(current_receiver(), N(str), (char *)keys[1], STRLEN(keys[1]), (char *)vals[1], STRLEN(vals[1]) ); assert(res != 0, "store bob" ); res = store_str(current_receiver(), N(str), (char *)keys[2], STRLEN(keys[2]), (char *)vals[2], STRLEN(vals[2]) ); assert(res != 0, "store carol" ); res = store_str(current_receiver(), N(str), (char *)keys[3], STRLEN(keys[3]), (char *)vals[3], STRLEN(vals[3]) ); assert(res != 0, "store dave" ); res = load_str(current_receiver(), current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), tmp, 64); assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "load alice"); res = load_str(current_receiver(), current_receiver(), N(str), (char *)keys[1], STRLEN(keys[1]), tmp, 64); assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "load bob"); res = load_str(current_receiver(), current_receiver(), N(str), (char *)keys[2], STRLEN(keys[2]), tmp, 64); assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "load carol"); res = load_str(current_receiver(), current_receiver(), N(str), (char *)keys[3], STRLEN(keys[3]), tmp, 64); assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "load dave"); res = previous_str(current_receiver(), current_receiver(), N(str), (char *)keys[3], STRLEN(keys[3]), tmp, 64); assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "back carol"); res = previous_str(current_receiver(), current_receiver(), N(str), (char *)keys[2], STRLEN(keys[2]), tmp, 64); assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "back dave"); res = previous_str(current_receiver(), current_receiver(), N(str), (char *)keys[1], STRLEN(keys[1]), tmp, 64); assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "back alice"); res = previous_str(current_receiver(), current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), tmp, 64); assert(res == -1, "no prev"); res = next_str(current_receiver(), current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), tmp, 64); assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "next bob"); res = next_str(current_receiver(), current_receiver(), N(str), (char *)keys[1], STRLEN(keys[1]), tmp, 64); assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "next carol"); res = next_str(current_receiver(), current_receiver(), N(str), (char *)keys[2], STRLEN(keys[2]), tmp, 64); assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "next dave"); res = next_str(current_receiver(), current_receiver(), N(str), (char *)keys[3], STRLEN(keys[3]), tmp, 64); assert(res == -1, "no next"); res = next_str(current_receiver(), current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), tmp, 0); assert(res == 0, "next 0"); /* res = front_str(current_receiver(), current_receiver(), N(str), tmp, 64); assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "front alice"); res = back_str(current_receiver(), current_receiver(), N(str), tmp, 64); assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "back dave"); */ res = lower_bound_str(current_receiver(), current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), tmp, 64); assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "lowerbound alice"); res = upper_bound_str(current_receiver(), current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), tmp, 64); assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "upperbound bob"); res = lower_bound_str(current_receiver(), current_receiver(), N(str), (char *)keys[3], STRLEN(keys[3]), tmp, 64); assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "upperbound dave"); res = upper_bound_str(current_receiver(), current_receiver(), N(str), (char *)keys[3], STRLEN(keys[3]), tmp, 64); assert(res == -1, "no upper_bound"); } void test_db::key_i64_general() { uint32_t res = 0; test_model alice{ N(alice), 20, 4234622}; test_model bob { N(bob), 15, 11932435}; test_model carol{ N(carol), 30, 545342453}; test_model dave { N(dave), 46, 6535354}; res = store_i64(current_receiver(), N(test_table), &dave, sizeof(test_model)); assert(res != 0, "store dave" ); res = store_i64(current_receiver(), N(test_table), &carol, sizeof(test_model)); assert(res != 0, "store carol" ); res = store_i64(current_receiver(), N(test_table), &bob, sizeof(test_model)); assert(res != 0, "store bob" ); res = store_i64(current_receiver(), N(test_table), &alice, sizeof(test_model)); assert(res != 0, "store alice" ); //fill with different ages in adjacent tables dave.age=123; store_i64(current_receiver(), N(test_tabld), &dave, sizeof(test_model)); dave.age=124; store_i64(current_receiver(), N(test_tablf), &dave, sizeof(test_model)); carol.age=125; store_i64(current_receiver(), N(test_tabld), &carol, sizeof(test_model)); carol.age=126; store_i64(current_receiver(), N(test_tablf), &carol, sizeof(test_model)); bob.age=127; store_i64(current_receiver(), N(test_tabld), &bob, sizeof(test_model)); bob.age=128; store_i64(current_receiver(), N(test_tablf), &bob, sizeof(test_model)); alice.age=129; store_i64(current_receiver(), N(test_tabld), &alice, sizeof(test_model)); alice.age=130; store_i64(current_receiver(), N(test_tablf), &alice, sizeof(test_model)); test_model tmp; res = front_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "front_i64 1"); my_memset(&tmp, 0, sizeof(test_model)); res = back_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "front_i64 2"); res = previous_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(carol) && tmp.age == 30 && tmp.phone == 545342453, "carol previous"); res = previous_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "bob previous"); res = previous_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "alice previous"); res = previous_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == 0, "previous null"); res = next_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "bob next"); res = next_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(carol) && tmp.age == 30 && tmp.phone == 545342453, "carol next"); res = next_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "dave next"); res = next_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == 0, "next null"); my_memset(&alice, 0, sizeof(test_model)); assert(alice.name == 0 && alice.age == 0 && alice.phone == 0, "my_memset"); alice.name = N(alice); res = load_i64(current_receiver(), current_receiver(), N(test_table), &alice, sizeof(test_model)); assert(res == sizeof(test_model) && alice.age == 20 && alice.phone == 4234622, "alice error 1"); alice.age = 21; alice.phone = 1234; res = store_i64(current_receiver(), N(test_table), &alice, sizeof(test_model)); assert(res == 0, "store alice 2" ); my_memset(&alice, 0, sizeof(test_model)); alice.name = N(alice); res = load_i64(current_receiver(), current_receiver(), N(test_table), &alice, sizeof(test_model)); assert(res == sizeof(test_model) && alice.age == 21 && alice.phone == 1234, "alice error 2"); my_memset(&bob, 0, sizeof(test_model)); bob.name = N(bob); my_memset(&carol, 0, sizeof(test_model)); carol.name = N(carol); my_memset(&dave, 0, sizeof(test_model)); dave.name = N(dave); res = load_i64(current_receiver(), current_receiver(), N(test_table), &bob, sizeof(test_model)); assert(res == sizeof(test_model) && bob.age == 15 && bob.phone == 11932435, "bob error 1"); res = load_i64(current_receiver(), current_receiver(), N(test_table), &carol, sizeof(test_model)); assert(res == sizeof(test_model) && carol.age == 30 && carol.phone == 545342453, "carol error 1"); res = load_i64(current_receiver(), current_receiver(), N(test_table), &dave, sizeof(test_model)); assert(res == sizeof(test_model) && dave.age == 46 && dave.phone == 6535354, "dave error 1"); res = load_i64(current_receiver(), N(other_code), N(test_table), &alice, sizeof(test_model)); assert(res == sizeof(test_model), "other_code"); res = load_i64(current_receiver(), current_receiver(), N(other_table), &alice, sizeof(test_model)); assert(res == 0, "other_table"); test_model_v2 alicev2; alicev2.name = N(alice); res = load_i64(current_receiver(), current_receiver(), N(test_table), &alicev2, sizeof(test_model_v2)); assert(res == sizeof(test_model) && alicev2.age == 21 && alicev2.phone == 1234, "alicev2 load"); alicev2.new_field = 66655444; res = store_i64(current_receiver(), N(test_table), &alicev2, sizeof(test_model_v2)); assert(res == 0, "store alice 3" ); my_memset(&alicev2, 0, sizeof(test_model_v2)); alicev2.name = N(alice); res = load_i64(current_receiver(), current_receiver(), N(test_table), &alicev2, sizeof(test_model_v2)); assert(res == sizeof(test_model_v2) && alicev2.age == 21 && alicev2.phone == 1234 && alicev2.new_field == 66655444, "alice model v2"); my_memset(&tmp, 0, sizeof(test_model)); tmp.name = N(bob); res = lower_bound_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(bob), "lower_bound_i64 bob" ); my_memset(&tmp, 0, sizeof(test_model)); tmp.name = N(boc); res = lower_bound_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(carol), "lower_bound_i64 carol" ); my_memset(&tmp, 0, sizeof(test_model)); tmp.name = N(dave); // data packet only big enough for name res = lower_bound_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(uint64_t) ); assert(res == sizeof(test_model) && tmp.name == N(dave), "lower_bound_i64 dave" ); my_memset(&tmp, 0, sizeof(test_model)); tmp.name = N(davf); res = lower_bound_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(uint64_t) ); assert(res == 0, "lower_bound_i64 fail" ); my_memset(&tmp, 0, sizeof(test_model)); tmp.name = N(alice); res = upper_bound_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.age == 15 && tmp.name == N(bob), "upper_bound_i64 bob" ); my_memset(&tmp, 0, sizeof(test_model)); tmp.name = N(dave); res = upper_bound_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == 0, "upper_bound_i64 dave" ); test_model_v3 tmp2; tmp2.name = N(alice); res = load_i64(current_receiver(), current_receiver(), N(test_table), &tmp2, sizeof(test_model_v3)); assert(res == sizeof(test_model_v2) && tmp2.age == 21 && tmp2.phone == 1234 && tmp2.new_field == 66655444, "load4update"); tmp2.another_field = 221122; res = update_i64(current_receiver(), N(test_table), &tmp2, sizeof(test_model_v3)); assert(res == 1, "update_i64"); res = load_i64(current_receiver(), current_receiver(), N(test_table), &tmp2, sizeof(test_model_v3)); assert(res == sizeof(test_model_v3) && tmp2.age == 21 && tmp2.phone == 1234 && tmp2.new_field == 66655444 && tmp2.another_field == 221122, "load4update"); tmp2.age = 11; res = update_i64(current_receiver(), N(test_table), &tmp2, sizeof(uint64_t)+1 ); assert(res == 1, "update_i64 small"); res = load_i64(current_receiver(), current_receiver(), N(test_table), &tmp2, sizeof(test_model_v3)); assert(res == sizeof(test_model_v3) && tmp2.age == 11 && tmp2.phone == 1234 && tmp2.new_field == 66655444 && tmp2.another_field == 221122, "load_i64 update_i64"); //Remove dummy records uint64_t tables[] { N(test_tabld), N(test_tablf) }; for(auto& t : tables) { while( front_i64( current_receiver(), current_receiver(), t, &tmp, sizeof(test_model) ) != 0 ) { remove_i64(current_receiver(), t, &tmp); } } } void test_db::key_i64_remove_all() { uint32_t res = 0; uint64_t key; key = N(alice); res = remove_i64(current_receiver(), N(test_table), &key); assert(res == 1, "remove alice"); key = N(bob); res = remove_i64(current_receiver(), N(test_table), &key); assert(res == 1, "remove bob"); key = N(carol); res = remove_i64(current_receiver(), N(test_table), &key); assert(res == 1, "remove carol"); key = N(dave); res = remove_i64(current_receiver(), N(test_table), &key); assert(res == 1, "remove dave"); test_model tmp; res = front_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == 0, "front_i64 remove"); res = back_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); assert(res == 0, "back_i64_i64 remove"); key = N(alice); res = remove_i64(current_receiver(), N(test_table), &key); assert(res == 0, "remove alice 1"); key = N(bob); res = remove_i64(current_receiver(), N(test_table), &key); assert(res == 0, "remove bob 1"); key = N(carol); res = remove_i64(current_receiver(), N(test_table), &key); assert(res == 0, "remove carol 1"); key = N(dave); res = remove_i64(current_receiver(), N(test_table), &key); assert(res == 0, "remove dave 1"); } void test_db::key_i64_small_load() { uint64_t dummy = 0; test_model alice{ N(alice), 20, 4234622}; // shouldn't throw an error, short circuits out because no table id is found auto res = load_i64(current_receiver(), current_receiver(), N(just_uint64), &dummy, sizeof(uint64_t)-1); assert(res == 0, "should have returned 0 on failure"); store_i64(current_receiver(), N(test_table), &alice, sizeof(test_model)); load_i64(current_receiver(), current_receiver(), N(test_table), &alice, sizeof(uint64_t)-1); } void test_db::key_i64_small_store() { uint64_t dummy = 0; store_i64(current_receiver(), N(just_uint64), &dummy, sizeof(uint64_t)-1); } void test_db::key_i64_store_scope() { uint64_t dummy = 0; store_i64(current_receiver(), N(just_uint64), &dummy, sizeof(uint64_t)); } void test_db::key_i64_remove_scope() { uint64_t dummy = 0; store_i64(current_receiver(), N(just_uint64), &dummy, sizeof(uint64_t)); } void test_db::key_i64_not_found() { uint64_t dummy = 1000; auto res = load_i64(current_receiver(), current_receiver(), N(just_uint64), &dummy, sizeof(uint64_t)); assert(res == 0, "i64_not_found load"); res = remove_i64(current_receiver(), N(just_uint64), &dummy); assert(res == 0, "i64_not_found remove"); } void test_db::key_i64_front_back() { uint32_t res = 0; test_model dave { N(dave), 46, 6535354}; test_model carol{ N(carol), 30, 545342453}; store_i64(current_receiver(), N(b), &dave, sizeof(test_model)); store_i64(current_receiver(), N(b), &carol, sizeof(test_model)); test_model bob { N(bob), 15, 11932435}; test_model alice{ N(alice), 20, 4234622}; store_i64(current_receiver(), N(a), &bob, sizeof(test_model)); store_i64(current_receiver(), N(a), &alice, sizeof(test_model)); test_model tmp; my_memset(&tmp, 0, sizeof(test_model)); res = front_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 1"); my_memset(&tmp, 0, sizeof(test_model)); res = back_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "key_i64_front 2"); my_memset(&tmp, 0, sizeof(test_model)); res = front_i64( current_receiver(), current_receiver(), N(b), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(carol) && tmp.age == 30 && tmp.phone == 545342453, "key_i64_front 3"); my_memset(&tmp, 0, sizeof(test_model)); res = back_i64( current_receiver(), current_receiver(), N(b), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "key_i64_front 4"); uint64_t key = N(carol); remove_i64(current_receiver(), N(b), &key); my_memset(&tmp, 0, sizeof(test_model)); res = front_i64( current_receiver(), current_receiver(), N(b), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "key_i64_front 5"); my_memset(&tmp, 0, sizeof(test_model)); res = back_i64( current_receiver(), current_receiver(), N(b), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "key_i64_front 6"); my_memset(&tmp, 0, sizeof(test_model)); res = front_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 7"); my_memset(&tmp, 0, sizeof(test_model)); res = back_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "key_i64_front 8"); key = N(dave); remove_i64(current_receiver(), N(b), &key); res = front_i64( current_receiver(), current_receiver(), N(b), &tmp, sizeof(test_model) ); assert(res == 0, "key_i64_front 9"); res = back_i64( current_receiver(), current_receiver(), N(b), &tmp, sizeof(test_model) ); assert(res == 0, "key_i64_front 10"); key = N(bob); remove_i64(current_receiver(), N(a), &key); my_memset(&tmp, 0, sizeof(test_model)); res = front_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 11"); my_memset(&tmp, 0, sizeof(test_model)); res = back_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 12"); key = N(alice); remove_i64(current_receiver(), N(a), &key); res = front_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); assert(res == 0, "key_i64_front 13"); res = back_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); assert(res == 0, "key_i64_front 14"); } uint32_t store_set_in_table(uint64_t table_name) { uint32_t res = 0; TestModel128x2 alice0{0, 500, N(alice0), table_name}; TestModel128x2 alice1{1, 400, N(alice1), table_name}; TestModel128x2 alice2{2, 300, N(alice2), table_name}; TestModel128x2 alice22{2, 200, N(alice33), table_name}; res = store_i128i128(current_receiver(), table_name, &alice0, sizeof(TestModel128x2)); assert(res == 1, "store alice0" ); res = store_i128i128(current_receiver(), table_name, &alice1, sizeof(TestModel128x2)); assert(res == 1, "store alice1" ); res = store_i128i128(current_receiver(), table_name, &alice2, sizeof(TestModel128x2)); assert(res == 1, "store alice2" ); res = store_i128i128(current_receiver(), table_name, &alice22, sizeof(TestModel128x2)); assert(res == 1, "store alice22" ); return res; TestModel128x2 bob0{10, 1, N(bob0), table_name}; TestModel128x2 bob1{11, 2, N(bob1), table_name}; TestModel128x2 bob2{12, 3, N(bob2), table_name}; TestModel128x2 bob3{13, 4, N(bob3), table_name}; res = store_i128i128(current_receiver(), table_name, &bob0, sizeof(TestModel128x2)); assert(res == 1, "store bob0" ); res = store_i128i128(current_receiver(), table_name, &bob1, sizeof(TestModel128x2)); assert(res == 1, "store bob1" ); res = store_i128i128(current_receiver(), table_name, &bob2, sizeof(TestModel128x2)); assert(res == 1, "store bob2" ); res = store_i128i128(current_receiver(), table_name, &bob3, sizeof(TestModel128x2)); assert(res == 1, "store bob3" ); TestModel128x2 carol0{20, 900, N(carol0), table_name}; TestModel128x2 carol1{21, 800, N(carol1), table_name}; TestModel128x2 carol2{22, 700, N(carol2), table_name}; TestModel128x2 carol3{23, 600, N(carol3), table_name}; res = store_i128i128(current_receiver(), table_name, &carol0, sizeof(TestModel128x2)); assert(res == 1, "store carol0" ); res = store_i128i128(current_receiver(), table_name, &carol1, sizeof(TestModel128x2)); assert(res == 1, "store carol1" ); res = store_i128i128(current_receiver(), table_name, &carol2, sizeof(TestModel128x2)); assert(res == 1, "store carol2" ); res = store_i128i128(current_receiver(), table_name, &carol3, sizeof(TestModel128x2)); assert(res == 1, "store carol3" ); TestModel128x2 dave0{30, 8, N(dave0), table_name}; TestModel128x2 dave1{31, 7, N(dave1), table_name}; TestModel128x2 dave2{32, 5, N(dave2), table_name}; TestModel128x2 dave3{33, 4, N(dave3), table_name}; res = store_i128i128(current_receiver(), table_name, &dave0, sizeof(TestModel128x2)); assert(res == 1, "store dave0" ); res = store_i128i128(current_receiver(), table_name, &dave1, sizeof(TestModel128x2)); assert(res == 1, "store dave1" ); res = store_i128i128(current_receiver(), table_name, &dave2, sizeof(TestModel128x2)); assert(res == 1, "store dave2" ); res = store_i128i128(current_receiver(), table_name, &dave3, sizeof(TestModel128x2)); assert(res == 1, "store dave3" ); return res; } void store_set_in_table(TestModel3xi64* records, int len, uint64_t table_name) { uint32_t res = 0; for( int i = 0; i < len; ++i ) { TestModel3xi64 *tmp = records+i; tmp->table = table_name; res = store_i64i64i64(current_receiver(), table_name, tmp, sizeof(TestModel3xi64)); assert(res == 1, "store_set_in_table" ); } } //TODO fix things #if 0 void test_db::key_i64i64i64_general() { uint32_t res = 0; TestModel3xi64 records[] = { {1, 1, 0, N()}, // 0 <--------------------------- {1, 1, 1, N()}, // 1 | {1, 2, 2, N()}, // 2 <--------------- | {2, 1, 3, N()}, // 3 | | {2, 2, 2, N()}, // 4 same {secondary,tertiary} | {2, 2, 5, N()}, // 5 | {3, 1, 6, N()}, // 6 | {4, 0, 7, N()}, // 7 | {4, 5, 8, N()}, // 8 | {5, 1, 9, N()}, // 9 | {5, 2, 0, N()}, //10 same {tertiary}------------- }; store_set_in_table(records, sizeof(records)/sizeof(records[0]), N(table1)); store_set_in_table(records, sizeof(records)/sizeof(records[0]), N(table2)); store_set_in_table(records, sizeof(records)/sizeof(records[0]), N(table3)); #define CALL(F, O, I, T, V) F##_##I##_##O(current_receiver(), current_receiver(), T, &V, sizeof(V)) #define LOAD(I, O, T, V) CALL(load, O, I, T, V) #define FRONT(I, O, T, V) CALL(front, O, I, T, V) #define BACK(I, O, T, V) CALL(back, O, I, T, V) #define NEXT(I, O, T, V) CALL(next, O, I, T, V) #define PREV(I, O, T, V) CALL(previous, O, I, T, V) #define UPPER(I, O, T, V) CALL(upper_bound, O, I, T, V) #define LOWER(I, O, T, V) CALL(lower_bound, O, I, T, V) #define LOGME 0 #define BS(X) ((X) ? "true" : "false") #define TABLE1_ASSERT(I, V, msg) \ if(LOGME) {\ eosio::print(msg, " : ", res, " a:", V.a, " b:", V.b, " c:", V.c, " t:", V.table, "inx:", uint64_t(I), " ("); \ eosio::print(BS(res == sizeof(V)), " ", BS(records[I].a == V.a), " ", BS(records[I].b == V.b), " ", BS(records[I].c == V.c), " => ", N(table2), ")\n"); \ } \ assert( res == sizeof(V) && records[I].a == V.a && records[I].b == V.b && \ records[I].c == V.c /*&& records[I].table == uint64_t(N(table2))*/, msg); #define LOAD_OK(I, O, T, INX, MSG) \ {eosio::remove_reference::type tmp; my_memset(&tmp, 0, sizeof(tmp));tmp = V; \ res = LOAD(I, O, T, tmp); \ TABLE1_ASSERT(INX, tmp, MSG)} #define LOAD_ER(I, O, T, MSG) \ {eosio::remove_reference::type tmp; my_memset(&tmp, 0, sizeof(tmp));tmp = V; \ res = LOAD(I, O, T, tmp); \ assert(res == -1, MSG)} #define FRONT_OK(I, O, T, INX, MSG) \ {eosio::remove_reference::type tmp; my_memset(&tmp, 0, sizeof(tmp));tmp = V; \ res = FRONT(I, O, T, tmp); \ TABLE1_ASSERT(INX, tmp, MSG)} #define BACK_OK(I, O, T, INX, MSG) \ {eosio::remove_reference::type tmp; my_memset(&tmp, 0, sizeof(tmp));tmp = V; \ res = BACK(I, O, T, tmp); \ TABLE1_ASSERT(INX, tmp, MSG)} TestModel3xi64 V; V={0}; LOAD_ER(primary, i64i64i64, N(table2), "i64x3 LOAD primary fail 0"); V={1}; LOAD_OK(primary, i64i64i64, N(table2), 0, "i64x3 LOAD primary 1"); V={2}; LOAD_OK(primary, i64i64i64, N(table2), 3, "i64x3 LOAD primary 2"); V={3}; LOAD_OK(primary, i64i64i64, N(table2), 6, "i64x3 LOAD primary 3"); V={4}; LOAD_OK(primary, i64i64i64, N(table2), 7, "i64x3 LOAD primary 4"); V={5}; LOAD_OK(primary, i64i64i64, N(table2), 9, "i64x3 LOAD primary 5"); V={6}; LOAD_ER(primary, i64i64i64, N(table2), "i64x3 LOAD primary fail 6"); V={11,0}; LOAD_OK(secondary, i64i64i64, N(table2), 7, "i64x3 LOAD secondary 0"); V={11,1}; LOAD_OK(secondary, i64i64i64, N(table2), 0, "i64x3 LOAD secondary 1"); V={11,2}; LOAD_OK(secondary, i64i64i64, N(table2),10, "i64x3 LOAD secondary 2"); V={11,3}; LOAD_ER(secondary, i64i64i64, N(table2), "i64x3 LOAD secondary fail 3"); V={11,4}; LOAD_ER(secondary, i64i64i64, N(table2), "i64x3 LOAD secondary fail 4"); V={11,5}; LOAD_OK(secondary, i64i64i64, N(table2), 8, "i64x3 LOAD secondary 5"); V={11,6}; LOAD_ER(secondary, i64i64i64, N(table2), "i64x3 LOAD secondary fail 6"); V={11,12,0}; LOAD_OK(tertiary, i64i64i64, N(table2), 0, "i64x3 LOAD tertiary 0"); V={11,12,1}; LOAD_OK(tertiary, i64i64i64, N(table2), 1, "i64x3 LOAD tertiary 1"); V={11,12,2}; LOAD_OK(tertiary, i64i64i64, N(table2), 2, "i64x3 LOAD tertiary 2"); V={11,12,3}; LOAD_OK(tertiary, i64i64i64, N(table2), 3, "i64x3 LOAD tertiary 3"); V={11,12,4}; LOAD_ER(tertiary, i64i64i64, N(table2), "i64x3 LOAD tertiary 4"); V={11,12,5}; LOAD_OK(tertiary, i64i64i64, N(table2), 5, "i64x3 LOAD tertiary 5"); V={11,12,6}; LOAD_OK(tertiary, i64i64i64, N(table2), 6, "i64x3 LOAD tertiary 6"); V={11,12,7}; LOAD_OK(tertiary, i64i64i64, N(table2), 7, "i64x3 LOAD tertiary 7"); V={11,12,8}; LOAD_OK(tertiary, i64i64i64, N(table2), 8, "i64x3 LOAD tertiary 8"); V={11,12,9}; LOAD_OK(tertiary, i64i64i64, N(table2), 9, "i64x3 LOAD tertiary 9"); V={11,12,10}; LOAD_ER(tertiary, i64i64i64, N(table2), "i64x3 LOAD tertiary 10"); V={11,12,11}; LOAD_ER(tertiary, i64i64i64, N(table2), "i64x3 LOAD tertiary fail 11"); #define NEXT_ALL(I, O, T) \ { \ auto n = sizeof(I)/sizeof(I[0]); \ auto j = 0; \ do { \ eosio::remove_reference::type tmp = records[I[j]]; \ res = NEXT(I, i64i64i64, N(table2), tmp);\ if(j+1::type tmp = records[I[j]]; \ res = PREV(I, i64i64i64, N(table2), tmp);\ if(j>0){ TABLE1_ASSERT(I[j-1], tmp, "i64x3 PREV " #I " ok "); } \ else { assert(res == -1, "i64x3 PREV " #I " fail "); }\ } while(--j>0); \ } NEXT_ALL(primary, i64i64i64, N(table2)); NEXT_ALL(secondary, i64i64i64, N(table2)); NEXT_ALL(tertiary, i64i64i64, N(table2)); PREV_ALL(primary, i64i64i64, N(table2)); PREV_ALL(secondary, i64i64i64, N(table2)); PREV_ALL(tertiary, i64i64i64, N(table2)); FRONT_OK(primary, i64i64i64, N(table2), primary[0], "i64x3 FRONT primary"); FRONT_OK(secondary, i64i64i64, N(table2), secondary[0], "i64x3 FRONT secondary"); FRONT_OK(tertiary, i64i64i64, N(table2), tertiary[0], "i64x3 FRONT tertiary"); BACK_OK(primary, i64i64i64, N(table2), primary[10], "i64x3 BACK primary"); BACK_OK(secondary, i64i64i64, N(table2), secondary[10], "i64x3 BACK secondary"); BACK_OK(tertiary, i64i64i64, N(table2), tertiary[10], "i64x3 BACK tertiary"); #define LOWER_ALL(I, O, T) \ { \ auto n = sizeof(I##_lb)/sizeof(I##_lb[0]); \ auto j = 0; \ do { \ eosio::remove_reference::type tmp = records[j]; \ res = LOWER(I, i64i64i64, N(table2), tmp);\ TABLE1_ASSERT(I##_lb[j], tmp, "i64x3 LOWER " #I " ok ");\ } while(++j::type tmp = records[j]; \ res = UPPER(I, i64i64i64, N(table2), tmp);\ if(res == -1) { assert(I##_ub[j]==-1,"i64x3 UPPER " #I " fail ") } \ else { TABLE1_ASSERT(I##_ub[j], tmp, "i64x3 UPPER " #I " ok "); } \ } while(++j key + value bytes: 2528 Bytes // 1024 * 2 * (2528 + 32) char key[] = "0000abcdefghijklmnopqrstuvwxy"; const uint32_t value_size = 2498; char* value = static_cast(eosio::malloc(value_size)); value[4] = '\0'; for(int i = 0; i < 1024 * 2; ++i) { set_key_str(i, key); // set the value with the same prefix to be able to identify set_key_str(i, value); store_str(N(dblimits), N(dblstr), key, sizeof(key), value, value_size); } eosio::free(value); } void test_db::key_str_min_exceed_limit() { char key = '1'; char value = '1'; // assuming max memory: 5 MBytes // assuming row overhead: 16 Bytes // key length: 1 bytes // value length: 1 bytes // -> key + value bytes: 8 Bytes // 8 + 32 = 40 Bytes (not enough space) store_str(N(dblimits), N(dblstr), &key, 1, &value, 1); } void test_db::key_str_under_limit() { // assuming max memory: 5 MBytes // assuming row overhead: 16 Bytes // key length: 30 bytes // value length: 2489 bytes // -> key + value bytes: 2520 Bytes // 1024 * 2 * (2520 + 32) = 5,226,496 => 16K bytes remaining char key[] = "0000abcdefghijklmnopqrstuvwxy"; const uint32_t value_size = 2489; char* value = static_cast(eosio::malloc(value_size)); value[4] = '\0'; for(int i = 0; i < 1024 * 2; ++i) { set_key_str(i, key); // set the value with the same prefix to be able to identify set_key_str(i, value); store_str(N(dblimits), N(dblstr), key, sizeof(key), value, value_size); } eosio::free(value); } void test_db::key_str_available_space_exceed_limit() { // key length: 30 bytes // value length: 16323 bytes // -> key + value bytes: 16360 Bytes (rounded to byte boundary) // 16,392 Bytes => exceeds 16K bytes remaining char key[] = "0000abcdefghijklmnopqrstuvwxy"; set_key_str(9999, key); const uint32_t value_size = 16323; char* value = static_cast(eosio::malloc(value_size)); store_str(N(dblimits), N(dblstr), key, sizeof(key), value, value_size); eosio::free(value); } void test_db::key_str_another_under_limit() { // 16K bytes remaining // key length: 30 bytes // value length: 18873 bytes // -> key + value bytes: 18904 Bytes (rounded to byte boundary) // 16,384 Bytes => just under 16K bytes remaining char key[] = "0000abcdefghijklmnopqrstuvwxy"; set_key_str(0, key); uint32_t value_size = 18873; char* value = static_cast(eosio::malloc(value_size)); update_str(N(dblimits), N(dblstr), key, sizeof(key), value, value_size); // 0 bytes remaining // key length: 30 bytes // value length: 2489 bytes // -> key + value bytes: 2520 Bytes set_key_str(1, key); remove_str(N(dblimits), N(dblstr), key, sizeof(key)); // 2,552 Bytes remaining // leave too little room for 32 Byte overhead + (key + value = 8 Byte min) // key length: 30 bytes // value length: 4909 bytes // -> key + value bytes: 5040 Bytes value_size = 2489 + 2514; set_key_str(2, key); value = static_cast(eosio::realloc(value, value_size)); update_str(N(dblimits), N(dblstr), key, sizeof(key), value, value_size); eosio::free(value); } void test_db::key_i64_setup_limit() { // assuming max memory: 5M Bytes // assuming row overhead: 16 Bytes // key length: 8 bytes // value length: 315 * 8 bytes (rounded to byte boundary) // -> key + value bytes: 2528 Bytes // 1024 * 2 * (2528 + 32) = 5,242,880 const uint64_t value_size = 315 * sizeof(uint64_t) + 1; auto value = (uint64_t*)eosio::malloc(value_size); for(int i = 0; i < 1024 * 2; ++i) { value[0] = i; store_i64(N(dblimits), N(dbli64), (char*)value, value_size); } eosio::free(value); } void test_db::key_i64_min_exceed_limit() { // will allocate 8 + 32 Bytes // at 5M Byte limit, so cannot store anything uint64_t value = (uint64_t)-1; store_i64(N(dblimits), N(dbli64), (char*)&value, sizeof(uint64_t)); } void test_db::key_i64_under_limit() { // updating keys' values // key length: 8 bytes // value length: 299 * 8 bytes // -> key + value bytes: 2400 Bytes // 1024 * 2 * (2400 + 32) = 4,980,736 const uint64_t value_size = 300 * sizeof(uint64_t); auto value = (uint64_t*)eosio::malloc(value_size); for(int i = 0; i < 1024 * 2; ++i) { value[0] = i; store_i64(N(dblimits), N(dbli64), (char*)value, value_size); } // 262,144 Bytes remaining eosio::free(value); } void test_db::key_i64_available_space_exceed_limit() { // 262,144 Bytes remaining // key length: 8 bytes // value length: 32764 * 8 bytes // -> key + value bytes: 262,120 Bytes // storing 262,152 Bytes exceeds remaining const uint64_t value_size = 32765 * sizeof(uint64_t); auto value = (uint64_t*)eosio::malloc(value_size); value[0] = 1024 * 2; store_i64(N(dblimits), N(dbli64), (char*)value, value_size); eosio::free(value); } void test_db::key_i64_another_under_limit() { // 262,144 Bytes remaining // key length: 8 bytes // value length: 33067 * 8 bytes (rounded to byte boundary) // -> key + value bytes: 264,544 Bytes // replacing storage bytes so 264,544 - 2400 = 262,144 Bytes (0 Bytes remaining) uint64_t value_size = 33067 * sizeof(uint64_t) + 7; auto value = (uint64_t*)eosio::malloc(value_size); value[0] = 15; update_i64(N(dblimits), N(dbli64), (char*)value, value_size); // 0 Bytes remaining // key length: 8 bytes // previous value length: 299 * 8 bytes // -> key + value bytes: 2400 Bytes // free up 2,432 Bytes value[0] = 14; remove_i64(N(dblimits), N(dbli64), (char*)value); // 2,432 Bytes remaining // key length: 8 bytes // previous value length: 294 * 8 bytes (rounded to byte boundary) // -> key + value bytes: 2,368 Bytes // 2,400 Bytes allocated value_size = 295 * sizeof(uint64_t) + 3; value = (uint64_t*)eosio::realloc(value, value_size); value[0] = 1024 * 2; store_i64(N(dblimits), N(dbli64), (char*)value, value_size); // 32 Bytes remaining (smallest row entry is 40 Bytes) eosio::free(value); } void test_db::key_i128i128_setup_limit() { // assuming max memory: 5M Bytes // assuming row overhead: 16 Bytes // keys length: 32 bytes // value length: 312 * 8 bytes (rounded to byte boundary) // -> key + value bytes: 2528 Bytes // 1024 * 2 * (2528 + 32) = 5,242,880 const uint64_t value_size = 315 * sizeof(uint64_t) + 1; auto value = (uint128_t*)eosio::malloc(value_size); for(int i = 0; i < 1024 * 2; ++i) { value[0] = i; value[1] = value[0] + 1; store_i128i128(N(dblimits), N(dbli128i128), (char*)value, value_size); } eosio::free(value); } void test_db::key_i128i128_min_exceed_limit() { // will allocate 32 + 32 Bytes // at 5M Byte limit, so cannot store anything const uint64_t value_size = 2 * sizeof(uint128_t); auto value = (uint128_t*)eosio::malloc(value_size); value[0] = (uint128_t)-1; value[1] = value[0] + 1; store_i128i128(N(dblimits), N(dbli128i128), (char*)&value, value_size); } void test_db::key_i128i128_under_limit() { // updating keys' values // keys length: 32 bytes // value length: 296 * 8 bytes // -> key + value bytes: 2400 Bytes // 1024 * 2 * (2400 + 32) = 4,980,736 const uint64_t value_size = 300 * sizeof(uint64_t); auto value = (uint128_t*)eosio::malloc(value_size); for(int i = 0; i < 1024 * 2; ++i) { value[0] = i; value[1] = value[0] + 1; store_i128i128(N(dblimits), N(dbli128i128), (char*)value, value_size); } // 262,144 Bytes remaining eosio::free(value); } void test_db::key_i128i128_available_space_exceed_limit() { // 262,144 Bytes remaining // keys length: 32 bytes // value length: 32761 * 8 bytes // -> key + value bytes: 262,120 Bytes // storing 262,152 Bytes exceeds remaining const uint64_t value_size = 32765 * sizeof(uint64_t); auto value = (uint128_t*)eosio::malloc(value_size); value[0] = 1024 * 2; value[1] = value[0] + 1; store_i128i128(N(dblimits), N(dbli128i128), (char*)value, value_size); eosio::free(value); } void test_db::key_i128i128_another_under_limit() { // 262,144 Bytes remaining // keys length: 32 bytes // value length: 33064 * 8 bytes (rounded to byte boundary) // -> key + value bytes: 264,544 Bytes // replacing storage bytes so 264,544 - 2400 = 262,144 Bytes (0 Bytes remaining) uint64_t value_size = 33067 * sizeof(uint64_t) + 7; auto value = (uint128_t*)eosio::malloc(value_size); value[0] = 15; value[1] = value[0] + 1; update_i128i128(N(dblimits), N(dbli128i128), (char*)value, value_size); // 0 Bytes remaining // keys length: 32 bytes // previous value length: 296 * 8 bytes // -> key + value bytes: 2400 Bytes // free up 2,432 Bytes value[0] = 14; value[1] = value[0] + 1; remove_i128i128(N(dblimits), N(dbli128i128), (char*)value); // 2,432 Bytes remaining // keys length: 32 bytes // previous value length: 288 * 8 bytes (rounded to byte boundary) // -> key + value bytes: 2,344 Bytes // 2,376 Bytes allocated value_size = 292 * sizeof(uint64_t) + 3; value = (uint128_t*)eosio::realloc(value, value_size); value[0] = 1024 * 2; value[1] = value[0] + 1; store_i128i128(N(dblimits), N(dbli128i128), (char*)value, value_size); // 56 Bytes remaining (smallest row entry is 64 Bytes) eosio::free(value); } void test_db::key_i64i64i64_setup_limit() { // assuming max memory: 5M Bytes // assuming row overhead: 16 Bytes // keys length: 24 bytes // value length: 313 * 8 bytes (rounded to byte boundary) // -> key + value bytes: 2528 Bytes // 1024 * 2 * (2528 + 32) = 5,242,880 const uint64_t value_size = 315 * sizeof(uint64_t) + 1; auto value = (uint64_t*)eosio::malloc(value_size); for(int i = 0; i < 1024 * 2; ++i) { value[0] = i; value[1] = value[0] + 1; value[2] = value[0] + 2; store_i64i64i64(N(dblimits), N(dbli64i64i64), (char*)value, value_size); } eosio::free(value); } void test_db::key_i64i64i64_min_exceed_limit() { // will allocate 24 + 32 Bytes // at 5M Byte limit, so cannot store anything const uint64_t value_size = 3 * sizeof(uint64_t); auto value = (uint64_t*)eosio::malloc(value_size); value[0] = (uint64_t)-1; value[1] = value[0] + 1; value[2] = value[0] + 2; store_i64i64i64(N(dblimits), N(dbli64i64i64), (char*)&value, value_size); } void test_db::key_i64i64i64_under_limit() { // updating keys' values // keys length: 24 bytes // value length: 297 * 8 bytes // -> key + value bytes: 2400 Bytes // 1024 * 2 * (2400 + 32) = 4,980,736 const uint64_t value_size = 300 * sizeof(uint64_t); auto value = (uint64_t*)eosio::malloc(value_size); for(int i = 0; i < 1024 * 2; ++i) { value[0] = i; value[1] = value[0] + 1; value[2] = value[0] + 2; store_i64i64i64(N(dblimits), N(dbli64i64i64), (char*)value, value_size); } // 262,144 Bytes remaining eosio::free(value); } void test_db::key_i64i64i64_available_space_exceed_limit() { // 262,144 Bytes remaining // keys length: 24 bytes // value length: 32762 * 8 bytes // -> key + value bytes: 262,120 Bytes // storing 262,152 Bytes exceeds remaining const uint64_t value_size = 32765 * sizeof(uint64_t); auto value = (uint64_t*)eosio::malloc(value_size); value[0] = 1024 * 2; value[1] = value[0] + 1; value[2] = value[0] + 2; store_i64i64i64(N(dblimits), N(dbli64i64i64), (char*)value, value_size); eosio::free(value); } void test_db::key_i64i64i64_another_under_limit() { // 262,144 Bytes remaining // keys length: 24 bytes // value length: 33065 * 8 bytes (rounded to byte boundary) // -> key + value bytes: 264,544 Bytes // replacing storage bytes so 264,544 - 2400 = 262,144 Bytes (0 Bytes remaining) uint64_t value_size = 33067 * sizeof(uint64_t) + 7; auto value = (uint64_t*)eosio::malloc(value_size); value[0] = 15; value[1] = value[0] + 1; value[2] = value[0] + 2; update_i64i64i64(N(dblimits), N(dbli64i64i64), (char*)value, value_size); // 0 Bytes remaining // keys length: 24 bytes // previous value length: 297 * 8 bytes // -> key + value bytes: 2400 Bytes // free up 2,432 Bytes value[0] = 14; value[1] = value[0] + 1; value[2] = value[0] + 2; remove_i64i64i64(N(dblimits), N(dbli64i64i64), (char*)value); // 2,432 Bytes remaining // keys length: 24 bytes // previous value length: 290 * 8 bytes (rounded to byte boundary) // -> key + value bytes: 2,352 Bytes // 2,384 Bytes allocated value_size = 295 * sizeof(uint64_t) + 3; value = (uint64_t*)eosio::realloc(value, value_size); value[0] = 1024 * 2; value[1] = value[0] + 1; value[2] = value[0] + 2; store_i64i64i64(N(dblimits), N(dbli64i64i64), (char*)value, value_size); // 48 Bytes remaining (smallest row entry is 56 Bytes) eosio::free(value); }