Wakati fulani uliopita tulikabiliwa na tatizo la kusafisha tuples katika nafasi
Mfano mzuri kwetu ulikuwa moduli ya tarantool inayoitwa
Description
Nyaraka za tarantool zina nzuri sana
Wacha tuanze kutoka mbali na tuangalie jinsi moduli iliyomalizika muda wake inaonekana kutoka nje:
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)
Kwa urahisi, tunazindua tarantool katika saraka ambapo maktaba yetu ya libcapped-expirationd.so iko. Vitendaji viwili vinasafirishwa kutoka kwa maktaba: anza na kuua. Hatua ya kwanza ni kufanya vipengele hivi vipatikane kutoka kwa Lua kwa kutumia box.schema.func.create na box.schema.user.grant. Kisha unda nafasi ambayo nakala zake zitakuwa na sehemu tatu tu: ya kwanza ni kitambulisho cha kipekee, ya pili ni barua pepe, na ya tatu ni maisha ya nakala. Tunajenga index ya mti juu ya shamba la kwanza na kuiita msingi. Ifuatayo tunapata kitu cha uunganisho kwenye maktaba yetu ya asili.
Baada ya kazi ya maandalizi, endesha kazi ya kuanza:
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})
Mfano huu utafanya kazi wakati wa skanning sawa kabisa na moduli iliyoisha muda wake, ambayo imeandikwa kwa Lua. Hoja ya kwanza kwa chaguo la kukokotoa la kuanza ni jina la kipekee la kazi. Ya pili ni kitambulisho cha nafasi. Ya tatu ni faharasa ya kipekee ambayo nakala zitafutwa. Ya nne ni fahirisi ambayo nakala zitapitiwa. Ya tano ni nambari ya uwanja wa tuple na maisha yote (kuhesabu huanza kutoka 1, sio 0!). Ya sita na ya saba ni mipangilio ya skanning. 1024 ndio idadi ya juu zaidi ya nakala zinazoweza kutazamwa katika muamala mmoja. 3600 - muda kamili wa kuchanganua kwa sekunde.
Kumbuka kuwa mfano hutumia faharasa sawa kwa kutambaa na kufuta. Ikiwa hii ni index ya mti, basi traversal inafanywa kutoka kwa ufunguo mdogo hadi mkubwa. Ikiwa kuna nyingine, kwa mfano, faharisi ya hashi, basi upitishaji unafanywa, kama sheria, kwa mpangilio wa nasibu. Nakala zote za nafasi huchanganuliwa katika tambazo moja.
Wacha tuingize nakala kadhaa kwenye nafasi na maisha ya sekunde 60:
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}
Wacha tuangalie ikiwa uingizaji ulifanikiwa:
tarantool> box.space.tester.index.primary:select()
---
- - [0, '[email protected]', 1576418976]
- [1, '[email protected]', 1576418976]
- [2, '[email protected]', 1576418976]
...
Wacha turudie chaguo baada ya sekunde 60+ (kuhesabu tangu mwanzo wa kuingizwa kwa nakala ya kwanza) na tuone kuwa moduli iliyomalizika muda wake tayari imechakatwa:
tarantool> box.space.tester.index.primary:select()
---
- []
...
Wacha tusitishe kazi:
capped_connection:call('libcapped-expirationd.kill', {'non-indexed'})
Wacha tuangalie mfano wa pili ambapo faharisi tofauti inatumika kwa utambazaji:
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)
Kila kitu hapa ni sawa na katika mfano wa kwanza, isipokuwa chache. Tunaunda index ya mti juu ya shamba la tatu na kuiita exp. Faharasa hii si lazima iwe ya kipekee, tofauti na faharasa inayoitwa msingi. Upitishaji utatekelezwa kwa faharasa ya exp, na kufutwa kwa msingi. Tunakumbuka kwamba hapo awali zote mbili zilifanywa kwa kutumia tu faharasa ya msingi.
Baada ya kazi ya maandalizi, tunaendesha kazi ya kuanza na hoja mpya:
capped_connection:call('libcapped-expirationd.start', {'indexed', box.space.tester.id, box.space.tester.index.primary, box.space.tester.index.exp, 3, 1024, 3600})
Wacha tuingize nakala kadhaa kwenye nafasi tena na maisha ya sekunde 60:
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}
Baada ya sekunde 30, kwa mlinganisho, tutaongeza nakala chache zaidi:
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}
Wacha tuangalie ikiwa uingizaji ulifanikiwa:
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]
...
Wacha turudie chaguo baada ya sekunde 60+ (kuhesabu tangu mwanzo wa kuingizwa kwa nakala ya kwanza) na tuone kuwa moduli iliyomalizika muda wake tayari imechakatwa:
tarantool> box.space.tester.index.primary:select()
---
- - [3, '[email protected]', 1576421287]
- [4, '[email protected]', 1576421287]
- [5, '[email protected]', 1576421287]
...
Bado kuna nakala zilizosalia kwenye nafasi ambazo zitakuwa na takriban sekunde 30 za kuishi. Zaidi ya hayo, skanisho ilikoma wakati wa kuhama kutoka kwenye tuple yenye kitambulisho cha 2 na maisha ya 1576421257 hadi kwenye tuple yenye kitambulisho cha 3 na maisha ya 1576421287. Tuples zilizo na maisha ya 1576421287 au zaidi hazikuchanganuliwa kutokana na kuagiza funguo za exp index. Hii ni akiba ambayo tulitaka kufikia mwanzoni kabisa.
Wacha tusitishe kazi:
capped_connection:call('libcapped-expirationd.kill', {'indexed'})
Utekelezaji
Njia bora ya kusema juu ya vipengele vyote vya mradi ni chanzo chake cha asili.
Hoja tunazopitisha kwa njia ya kuanza zimehifadhiwa katika muundo unaoitwa expiration_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;
};
Sifa ya jina ni jina la kazi. Sifa ya kitambulisho cha nafasi ni kitambulisho cha nafasi. rm_index_id sifa ni kitambulisho cha faharasa ya kipekee ambayo nakala zitafutwa. Sifa ya it_index_id ni kitambulisho cha faharasa ambayo nakala zitapitishwa. Sifa ya it_index_type ni aina ya faharasa ambayo nakala zitapitiwa. Sifa ya filed_no ni nambari ya sehemu ya tuple yenye maisha yote. Sifa ya ukubwa_changanuzi ni idadi ya juu zaidi ya nakala ambazo huchanganuliwa katika muamala mmoja. Sifa ya_muda wa kuchanganua ni muda kamili wa kuchanganua kwa sekunde.
Hatutazingatia kuchanganua hoja. Hii ni kazi ngumu lakini rahisi, ambayo maktaba itakusaidia
Tunaorodhesha prototypes za kazi zote ambazo hutumiwa kwa uchanganuzi:
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);
Sasa hebu tuendelee kwenye jambo muhimu zaidi - mantiki ya kupitisha nafasi na kufuta tuples. Kila sehemu ya nakala zisizozidi ukubwa wa scan_size huchanganuliwa na kurekebishwa chini ya muamala mmoja. Ikifaulu, muamala huu unafanywa; hitilafu ikitokea, inarejeshwa. Hoja ya mwisho kwa chaguo za kukokotoa za expirationd_iterate ni kielekezi kwa kiboreshaji ambapo uchanganuzi huanza au kuendelea. Kirudishi hiki kinaongezwa ndani hadi hitilafu hutokea, nafasi itaisha, au haiwezekani kusimamisha mchakato mapema. Chaguo za kukokotoa expirationd_expired hukagua maisha ya nakala, expirationd_delete hufuta nakala, expirationd_breakable hukagua kama tunahitaji kuendelea.
Nambari ya utendaji kazi expirationd_iterate:
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;
}
Msimbo wa kukokotoa umekwisha muda_umeisha:
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 msimbo wa kazi:
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);
}
Msimbo wa utendakazi 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;
}
Programu
Unaweza kutazama msimbo wa chanzo kwa
Chanzo: mapenzi.com