Beth amser yn ôl roeddem yn wynebu'r broblem o lanhau tuples mewn gofodau
Enghraifft dda i ni oedd y modiwl tarantool a elwir
Disgrifiad
Mae gan y ddogfennaeth ar gyfer tarantool dda iawn
Gadewch i ni ddechrau o bell ac edrych ar sut olwg sydd ar fodiwl sydd wedi dod i ben wedi'i gapio o'r tu allan:
fiber = require('fiber')
net_box = require('net.box')
box.cfg{listen = 3300}
box.schema.func.create('libcapped-expirationd.start', {language = 'C'})
box.schema.user.grant('guest', 'execute', 'function', 'libcapped-expirationd.start')
box.schema.func.create('libcapped-expirationd.kill', {language = 'C'})
box.schema.user.grant('guest', 'execute', 'function', 'libcapped-expirationd.kill')
box.schema.space.create('tester')
box.space.tester:create_index('primary', {unique = true, parts = {1, 'unsigned'}})
capped_connection = net_box:new(3300)
Er mwyn symlrwydd, rydym yn lansio tarantool yn y cyfeiriadur lle mae ein llyfrgell libcapped-expirationd.so wedi'i lleoli. Mae dwy swyddogaeth yn cael eu hallforio o'r llyfrgell: cychwyn a lladd. Y cam cyntaf yw sicrhau bod y swyddogaethau hyn ar gael gan Lua gan ddefnyddio box.schema.func.create a box.schema.user.grant. Yna creu gofod y bydd ei tuples yn cynnwys dim ond tri maes: y cyntaf yn ddynodwr unigryw, yr ail yw e-bost, a'r trydydd yw oes y tuple. Rydym yn adeiladu mynegai coed ar ben y cae cyntaf ac yn ei alw'n gynradd. Nesaf cawn y gwrthrych cysylltiad i'n llyfrgell frodorol.
Ar ôl y gwaith paratoi, rhedwch y swyddogaeth gychwyn:
capped_connection:call('libcapped-expirationd.start', {'non-indexed', box.space.tester.id, box.space.tester.index.primary, box.space.tester.index.primary, 3, 1024, 3600})
Bydd yr enghraifft hon yn gweithio yn ystod sganio yn union yr un fath â'r modiwl sydd wedi dod i ben, sydd wedi'i ysgrifennu yn Lua. Y ddadl gyntaf i'r swyddogaeth gychwyn yw enw unigryw'r dasg. Yr ail yw'r dynodwr gofod. Mae'r trydydd yn fynegai unigryw lle bydd tuples yn cael eu dileu. Y pedwerydd yw'r mynegai ar gyfer croesi'r tuples. Y pumed yw nifer y cae tuple ag oes (rhifo yn dechrau o 1, nid 0!). Mae'r chweched a'r seithfed yn osodiadau sganio. 1024 yw uchafswm nifer y tuples y gellir eu gweld mewn un trafodiad. 3600 - amser sgan llawn mewn eiliadau.
Sylwch fod yr enghraifft yn defnyddio'r un mynegai ar gyfer cropian a dileu. Os yw hwn yn fynegai coeden, yna mae'r llwybr yn cael ei wneud o'r cywair llai i'r un mwy. Os oes mynegai hash arall, er enghraifft, yna mae'r llwybr yn cael ei wneud, fel rheol, mewn trefn ar hap. Mae pob tuples gofod yn cael eu sganio mewn un sgan.
Gadewch i ni fewnosod sawl tuples yn y gofod gydag oes o 60 eiliad:
box.space.tester:insert{0, '[email protected]', math.floor(fiber.time()) + 60}
box.space.tester:insert{1, '[email protected]', math.floor(fiber.time()) + 60}
box.space.tester:insert{2, '[email protected]', math.floor(fiber.time()) + 60}
Gadewch i ni wirio bod y mewnosodiad yn llwyddiannus:
tarantool> box.space.tester.index.primary:select()
---
- - [0, '[email protected]', 1576418976]
- [1, '[email protected]', 1576418976]
- [2, '[email protected]', 1576418976]
...
Gadewch i ni ailadrodd y dewis ar ôl 60+ eiliad (gan gyfrif o ddechrau mewnosod y tuple cyntaf) a gweld bod y modiwl wedi'i gapio wedi dod i ben eisoes wedi prosesu:
tarantool> box.space.tester.index.primary:select()
---
- []
...
Gadewch i ni atal y dasg:
capped_connection:call('libcapped-expirationd.kill', {'non-indexed'})
Edrychwn ar ail enghraifft lle mae mynegai ar wahân yn cael ei ddefnyddio ar gyfer y cropian:
fiber = require('fiber')
net_box = require('net.box')
box.cfg{listen = 3300}
box.schema.func.create('libcapped-expirationd.start', {language = 'C'})
box.schema.user.grant('guest', 'execute', 'function', 'libcapped-expirationd.start')
box.schema.func.create('libcapped-expirationd.kill', {language = 'C'})
box.schema.user.grant('guest', 'execute', 'function', 'libcapped-expirationd.kill')
box.schema.space.create('tester')
box.space.tester:create_index('primary', {unique = true, parts = {1, 'unsigned'}})
box.space.tester:create_index('exp', {unique = false, parts = {3, 'unsigned'}})
capped_connection = net_box:new(3300)
Mae popeth yma yr un peth ag yn yr enghraifft gyntaf, gydag ychydig eithriadau. Rydym yn adeiladu mynegai coed ar ben y trydydd cae ac yn ei alw'n exp. Nid oes rhaid i'r mynegai hwn fod yn unigryw, yn wahanol i'r mynegai a elwir yn gynradd. Bydd tramwy yn cael ei wneud yn ôl mynegai exp, a dileu yn ôl cynradd. Cofiwn i'r ddau gael eu gwneud o'r blaen gan ddefnyddio'r mynegai cynradd yn unig.
Ar ôl y gwaith paratoi, rydym yn rhedeg y swyddogaeth gychwyn gyda dadleuon newydd:
capped_connection:call('libcapped-expirationd.start', {'indexed', box.space.tester.id, box.space.tester.index.primary, box.space.tester.index.exp, 3, 1024, 3600})
Gadewch i ni fewnosod sawl tuples yn y gofod eto gydag oes o 60 eiliad:
box.space.tester:insert{0, '[email protected]', math.floor(fiber.time()) + 60}
box.space.tester:insert{1, '[email protected]', math.floor(fiber.time()) + 60}
box.space.tester:insert{2, '[email protected]', math.floor(fiber.time()) + 60}
Ar ôl 30 eiliad, trwy gyfatebiaeth, byddwn yn ychwanegu ychydig mwy o tuples:
box.space.tester:insert{3, '[email protected]', math.floor(fiber.time()) + 60}
box.space.tester:insert{4, '[email protected]', math.floor(fiber.time()) + 60}
box.space.tester:insert{5, '[email protected]', math.floor(fiber.time()) + 60}
Gadewch i ni wirio bod y mewnosodiad yn llwyddiannus:
tarantool> box.space.tester.index.primary:select()
---
- - [0, '[email protected]', 1576421257]
- [1, '[email protected]', 1576421257]
- [2, '[email protected]', 1576421257]
- [3, '[email protected]', 1576421287]
- [4, '[email protected]', 1576421287]
- [5, '[email protected]', 1576421287]
...
Gadewch i ni ailadrodd y dewis ar ôl 60+ eiliad (gan gyfrif o ddechrau mewnosod y tuple cyntaf) a gweld bod y modiwl wedi'i gapio wedi dod i ben eisoes wedi prosesu:
tarantool> box.space.tester.index.primary:select()
---
- - [3, '[email protected]', 1576421287]
- [4, '[email protected]', 1576421287]
- [5, '[email protected]', 1576421287]
...
Mae yna rai tuples ar ôl yn y gofod o hyd a fydd â thua 30 eiliad arall i fyw. Ar ben hynny, daeth y sgan i ben wrth symud o hwll ag ID o 2 ac oes o 1576421257 i hwll ag ID o 3 ac oes o 1576421287. Ni sganiwyd twplau ag oes o 1576421287 neu fwy oherwydd archebu yr allweddi mynegai exp. Dyma’r arbedion yr oeddem am eu cyflawni ar y cychwyn cyntaf.
Gadewch i ni atal y dasg:
capped_connection:call('libcapped-expirationd.kill', {'indexed'})
Gweithredu
Y ffordd orau o ddweud am holl nodweddion prosiect yw ei ffynhonnell wreiddiol.
Mae'r dadleuon rydyn ni'n eu trosglwyddo i'r dull cychwyn yn cael eu storio mewn strwythur o'r enw expirationd_task:
struct expirationd_task
{
char name[256];
uint32_t space_id;
uint32_t rm_index_id;
uint32_t it_index_id;
uint32_t it_index_type;
uint32_t field_no;
uint32_t scan_size;
uint32_t scan_time;
};
Y briodwedd enw yw enw'r dasg. Y briodwedd space_id yw'r dynodwr gofod. Y briodwedd rm_index_id yw dynodwr y mynegai unigryw a ddefnyddir i ddileu tuples. Y briodwedd it_index_id yw dynodwr y mynegai a ddefnyddir i groesi tuples. Y briodwedd it_index_type yw'r math o fynegai y bydd tuples yn cael ei groesi drwyddo. Y briodwedd filed_no yw nifer y maes tuple ag oes. Y briodwedd scan_size yw'r nifer uchaf o duples sy'n cael eu sganio mewn un trafodiad. Y briodwedd scan_time yw'r amser sgan llawn mewn eiliadau.
Ni fyddwn yn ystyried dosrannu dadleuon. Mae hon yn waith manwl ond syml, a bydd y llyfrgell yn eich helpu chi
Rydym yn rhestru'r prototeipiau o'r holl swyddogaethau a ddefnyddir ar gyfer dosrannu:
bool expirationd_parse_name(struct expirationd_task *task, const char **pos);
bool expirationd_parse_space_id(struct expirationd_task *task, const char **pos);
bool expirationd_parse_rm_index_id(struct expirationd_task *task, const char **pos);
bool expirationd_parse_rm_index_unique(struct expirationd_task *task, const char **pos);
bool expirationd_parse_rm_index(struct expirationd_task *task, const char **pos);
bool expirationd_parse_it_index_id(struct expirationd_task *task, const char **pos);
bool expirationd_parse_it_index_type(struct expirationd_task *task, const char **pos);
bool expirationd_parse_it_index(struct expirationd_task *task, const char **pos);
bool expirationd_parse_field_no(struct expirationd_task *task, const char **pos);
bool expirationd_parse_scan_size(struct expirationd_task *task, const char **pos);
bool expirationd_parse_scan_time(struct expirationd_task *task, const char **pos);
Nawr, gadewch i ni symud ymlaen at y peth pwysicaf - y rhesymeg o osgoi gofod a dileu tuples. Mae pob bloc o tuples nad yw'n fwy na scan_size yn cael ei sganio a'i addasu o dan un trafodiad. Os yw'n llwyddiannus, mae'r trafodiad hwn wedi'i ymrwymo; os bydd gwall, caiff ei rolio'n ôl. Mae'r ddadl olaf i'r ffwythiant expirationd_iterate yn bwyntydd i'r iterator y mae'r sganio'n dechrau neu'n parhau ohono. Cynyddir yr iterator hwn yn fewnol nes bod gwall yn digwydd, mae'r gofod yn rhedeg allan, neu nid yw'n bosibl atal y broses ymlaen llaw. Mae'r ffwythiant expirationd_expired yn gwirio oes tuple, mae expirationd_delete yn dileu tuple, mae expirationd_breakable yn gwirio a oes angen i ni symud ymlaen.
Cod swyddogaeth_iterate_exppirationd:
static bool
expirationd_iterate(struct expirationd_task *task, box_iterator_t **iterp)
{
box_iterator_t *iter = *iterp;
box_txn_begin();
for (uint32_t i = 0; i < task->scan_size; ++i) {
box_tuple_t *tuple = NULL;
if (box_iterator_next(iter, &tuple) < 0) {
box_iterator_free(iter);
*iterp = NULL;
box_txn_rollback();
return false;
}
if (!tuple) {
box_iterator_free(iter);
*iterp = NULL;
box_txn_commit();
return true;
}
if (expirationd_expired(task, tuple))
expirationd_delete(task, tuple);
else if (expirationd_breakable(task))
break;
}
box_txn_commit();
return true;
}
Cod swyddogaeth wedi dod i ben_wedi dod i ben :
static bool
expirationd_expired(struct expirationd_task *task, box_tuple_t *tuple)
{
const char *buf = box_tuple_field(tuple, task->field_no - 1);
if (!buf || mp_typeof(*buf) != MP_UINT)
return false;
uint64_t val = mp_decode_uint(&buf);
if (val > fiber_time64() / 1000000)
return false;
return true;
}
Wedi dod i ben_dileu cod swyddogaeth:
static void
expirationd_delete(struct expirationd_task *task, box_tuple_t *tuple)
{
uint32_t len;
const char *str = box_tuple_extract_key(tuple, task->space_id, task->rm_index_id, &len);
box_delete(task->space_id, task->rm_index_id, str, str + len, NULL);
}
Cod swyddogaeth darfodadwy_breakable:
static bool
expirationd_breakable(struct expirationd_task *task)
{
return task->it_index_id != task->rm_index_id && task->it_index_type == ITER_GT;
}
Cais
Gallwch weld y cod ffynhonnell yn
Ffynhonnell: hab.com