Fyrir nokkru síðan stóðum við frammi fyrir því vandamáli að þrífa túpa í rýmum
Gott dæmi fyrir okkur var tarantool einingin sem heitir
Lýsing
Skjölin fyrir tarantool hafa mjög gott
Við skulum byrja úr fjarska og skoða hvernig eining með loki sem er útrunnið lítur út að utan:
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)
Til einföldunar ræsum við tarantool í möppunni þar sem libcapped-expirationd.so bókasafnið okkar er staðsett. Tvær aðgerðir eru fluttar út úr bókasafninu: byrja og drepa. Fyrsta skrefið er að gera þessar aðgerðir aðgengilegar frá Lua með því að nota box.schema.func.create og box.schema.user.grant. Búðu síðan til svæði þar sem túllarnir innihalda aðeins þrjá reiti: sá fyrsti er einstakt auðkenni, sá annar er tölvupóstur og sá þriðji er líftími túllsins. Við byggjum trjávísitölu ofan á fyrsta reitinn og köllum það aðal. Næst fáum við tengingarhlutinn í innfædda bókasafnið okkar.
Eftir undirbúningsvinnu skaltu keyra byrjunaraðgerðina:
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})
Þetta dæmi mun virka við skönnun nákvæmlega eins og útrunninn eining, sem er skrifuð í Lua. Fyrstu rökin fyrir upphafsfallinu eru einstakt heiti verkefnisins. Annað er rýmisauðkennið. Þriðja er einstök vísitala þar sem túllum verður eytt. Fjórða er vísitalan sem farið verður yfir túpurnar. Það fimmta er númer tuple reitsins með líftíma (talning byrjar frá 1, ekki 0!). Sjötta og sjöunda eru skönnunarstillingar. 1024 er hámarksfjöldi tuples sem hægt er að skoða í einni færslu. 3600 — fullur skannatími í sekúndum.
Athugaðu að dæmið notar sömu vísitölu til að skríða og eyða. Ef þetta er trjávísitala, þá fer yfirferðin frá minni lyklinum yfir í þann stærri. Ef það er einhver önnur, til dæmis kjötkássavísitala, þá fer yfirferðin að jafnaði fram í handahófskenndri röð. Allir geimtúllur eru skannaðar í einni skönnun.
Við skulum setja nokkra tuple inn í rýmið með líftíma upp á 60 sekúndur:
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}
Við skulum athuga hvort innsetningin hafi tekist:
tarantool> box.space.tester.index.primary:select()
---
- - [0, '[email protected]', 1576418976]
- [1, '[email protected]', 1576418976]
- [2, '[email protected]', 1576418976]
...
Við skulum endurtaka valið eftir 60+ sekúndur (talið frá upphafi innsetningar fyrsta túpunnar) og sjáum að lokuð útrunnin eining hefur þegar unnið:
tarantool> box.space.tester.index.primary:select()
---
- []
...
Hættum verkefninu:
capped_connection:call('libcapped-expirationd.kill', {'non-indexed'})
Við skulum skoða annað dæmi þar sem sérstök vísitala er notuð fyrir skrið:
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)
Hér er allt eins og í fyrra dæminu, með nokkrum undantekningum. Við byggjum trjávísitölu ofan á þriðja reitinn og köllum það exp. Þessi vísitala þarf ekki að vera einstök, ólíkt þeirri vísitölu sem kallast aðal. Flutningur verður framkvæmdur með exp index, og eyðing með aðal. Við munum að áður var hvort tveggja gert með því að nota aðalvísitöluna.
Eftir undirbúningsvinnuna keyrum við byrjunarfallið með nýjum rökum:
capped_connection:call('libcapped-expirationd.start', {'indexed', box.space.tester.id, box.space.tester.index.primary, box.space.tester.index.exp, 3, 1024, 3600})
Við skulum setja nokkra tuple inn í rýmið aftur með líftíma upp á 60 sekúndur:
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}
Eftir 30 sekúndur, á hliðstæðan hátt, munum við bæta við nokkrum túllum í viðbót:
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}
Við skulum athuga hvort innsetningin hafi tekist:
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]
...
Við skulum endurtaka valið eftir 60+ sekúndur (talið frá upphafi innsetningar fyrsta túpunnar) og sjáum að lokuð útrunnin eining hefur þegar unnið:
tarantool> box.space.tester.index.primary:select()
---
- - [3, '[email protected]', 1576421287]
- [4, '[email protected]', 1576421287]
- [5, '[email protected]', 1576421287]
...
Það eru enn nokkrir túplar eftir í rýminu sem munu hafa um það bil 30 sekúndur í viðbót til að lifa. Ennfremur stöðvaðist skönnun þegar farið var úr túllu með auðkenni 2 og líftíma 1576421257 í túllu með auðkenni 3 og líftíma 1576421287. Túpelar með líftíma 1576421287 eða meira voru ekki skannaðar vegna pöntunar á exp index lyklana. Þetta er sparnaðurinn sem við vildum ná strax í upphafi.
Hættum verkefninu:
capped_connection:call('libcapped-expirationd.kill', {'indexed'})
Framkvæmd
Besta leiðin til að segja frá öllum eiginleikum verkefnis er upprunaleg heimild þess.
Rökin sem við sendum til upphafsaðferðarinnar eru geymd í uppbyggingu sem kallast 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;
};
Nafnaeigindið er heiti verkefnisins. Eigindið space_id er auðkenni rýmis. Eigindin rm_index_id er auðkenni einstaka vísitölunnar sem túllum verður eytt með. Eigindin it_index_id er auðkenni vísitölunnar sem farið verður í gegnum tuples. Eigindin it_index_type er tegund vísitölunnar sem farið verður í gegnum tuples. Filed_no eigindin er númer tuple reitsins með líftíma. Scan_size eigindin er hámarksfjöldi tuples sem eru skannaðar í einni færslu. Scan_time eigindin er fullur skannatími í sekúndum.
Við munum ekki íhuga að flokka rök. Þetta er vandað en einfalt starf, sem bókasafnið mun hjálpa þér með
Við skráum frumgerðir allra aðgerða sem eru notaðar við þáttun:
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);
Nú skulum við halda áfram að því mikilvægasta - rökfræðinni um að fara framhjá plássi og eyða túllum. Hver blokk af túllum sem ekki eru stærri en scan_size er skannaður og breytt í einni færslu. Ef vel tekst til er þessi viðskipti framin; ef villa kemur upp er henni snúið til baka. Síðasta rökin við expirationd_iterate fallið er bendi á endurtekið sem skönnun hefst eða heldur áfram frá. Þessi endurtekning er aukinn innbyrðis þar til villa kemur upp, plássið klárast eða ekki er hægt að stöðva ferlið fyrirfram. Aðgerðin expirationd_expired athugar líftíma tuple, expirationd_delete eyðir tuple, expirationd_breakable athugar hvort við þurfum að halda áfram.
Expirationd_iterate aðgerðakóði:
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;
}
Aðgerðarkóði expirationd_expired:
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;
}
Expirationd_delete aðgerðakóði:
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);
}
Aðgerðarkóði expiration_breakable:
static bool
expirationd_breakable(struct expirationd_task *task)
{
return task->it_index_id != task->rm_index_id && task->it_index_type == ITER_GT;
}
umsókn
Þú getur skoðað frumkóðann á
Heimild: www.habr.com