Duela denbora pixka bat espazioetan tupleak garbitzearen arazoarekin topo egin genuen
Adibide ona guretzat izeneko tarantool modulua izan zen
Description
Tarantoolaren dokumentazioak oso ona du
Has gaitezen urrunetik eta begira gaitezen iraungitze-modulu bat kanpotik nolakoa den:
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)
Sinpletasuna lortzeko, tarantool abiarazten dugu gure libcapped-expirationd.so liburutegia dagoen direktorioan. Liburutegitik bi funtzio esportatzen dira: hasi eta hil. Lehen urratsa funtzio hauek Lua-tik eskuragarri jartzea da, box.schema.func.create eta box.schema.user.grant erabiliz. Ondoren, sortu espazio bat zeinen tuplek hiru eremu baino ez dituzten izango: lehenengoa identifikatzaile bakarra da, bigarrena posta elektronikoa eta hirugarrena tuplaren bizitza. Lehenengo eremuaren gainean zuhaitz-indize bat eraikitzen dugu eta lehen deitzen diogu. Ondoren, konexio objektua gure jatorrizko liburutegira jasoko dugu.
Prestaketa lanak egin ondoren, exekutatu hasiera funtzioa:
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})
Adibide honek eskaneatzean iraungitako moduluaren berdin funtzionatuko du, Lua-n idatzita dagoena. Hasierako funtzioaren lehen argumentua zereginaren izen bakarra da. Bigarrena espazioaren identifikatzailea da. Hirugarrena tuplak ezabatuko diren indize bakarra da. Laugarrena tuplak zeharkatuko dituen indizea da. Bosgarrena bizitza-denbora duen tupla eremuaren zenbakia da (zenbaketa 1etik hasten da, ez 0tik!). Seigarrena eta zazpigarrena eskaneatzeko ezarpenak dira. 1024 transakzio bakarrean ikus daitezkeen tupla kopurua da. 3600 β eskaneatu denbora osoa segundotan.
Kontuan izan adibideak indize bera erabiltzen duela arakatzeko eta ezabatzeko. Hau zuhaitz-indizea bada, zeharkatzea gako txikiagotik handiagora egiten da. Beste bat bada, adibidez, hash indizea, orduan zeharkatzea, oro har, ausazko ordenan egiten da. Espazio-tupla guztiak eskaneatzen dira eskaneatu batean.
Sar ditzagun hainbat tupla espazioan 60 segundoko bizitzarekin:
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}
Egiaztatu dezagun txertaketa arrakastatsua izan dela:
tarantool> box.space.tester.index.primary:select()
---
- - [0, '[email protected]', 1576418976]
- [1, '[email protected]', 1576418976]
- [2, '[email protected]', 1576418976]
...
Errepikatu dezagun aukeraketa 60 segundo baino gehiago igaro ondoren (lehen tuplaren txertaketaren hasieratik zenbatuta) eta ikus dezagun mugatutako iraungitze modulua dagoeneko prozesatu dela:
tarantool> box.space.tester.index.primary:select()
---
- []
...
Utz dezagun zeregina:
capped_connection:call('libcapped-expirationd.kill', {'non-indexed'})
Ikus dezagun bigarren adibide bat arakatzeko indize bereizia erabiltzen den:
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)
Hemen dena lehen adibideko berdina da, salbuespenak salbuespen. Hirugarren eremuaren gainean zuhaitz-indize bat eraikitzen dugu eta exp deitzen diogu. Indize honek ez du zertan bakarra izan, primario deritzon indizeak ez bezala. Zeharkaldia exp indizearen bidez egingo da, eta ezabaketa primarioaren bidez. Gogoratzen dugu lehen biak indize primarioa soilik erabiliz egiten zirela.
Prestaketa lanaren ondoren, hasierako funtzioa exekutatzen dugu argumentu berriekin:
capped_connection:call('libcapped-expirationd.start', {'indexed', box.space.tester.id, box.space.tester.index.primary, box.space.tester.index.exp, 3, 1024, 3600})
Sar ditzagun hainbat tupla espazioan berriro 60 segundoko bizitzarekin:
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}
30 segundo igaro ondoren, analogiaz, tupla batzuk gehituko ditugu:
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}
Egiaztatu dezagun txertaketa arrakastatsua izan dela:
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]
...
Errepikatu dezagun aukeraketa 60 segundo baino gehiago igaro ondoren (lehen tuplaren txertaketaren hasieratik zenbatuta) eta ikus dezagun mugatutako iraungitze modulua dagoeneko prozesatu dela:
tarantool> box.space.tester.index.primary:select()
---
- - [3, '[email protected]', 1576421287]
- [4, '[email protected]', 1576421287]
- [5, '[email protected]', 1576421287]
...
Oraindik 30 segundo inguru bizitzeko gehiago izango duten tupla batzuk geratzen dira espazioan. Gainera, 2 ID eta 1576421257 bizitzako tupla batetik 3 ID eta 1576421287 bizitzako tupla batera igarotzean gelditu zen. exp indizearen teklak. Hau da hasiera-hasieran lortu nahi genuen aurrezkia.
Utz dezagun zeregina:
capped_connection:call('libcapped-expirationd.kill', {'indexed'})
Inplementazioa
Proiektu baten ezaugarri guztiak kontatzeko modurik onena jatorrizko iturria da.
Hasiera metodoari pasatzen dizkiogun argumentuak expirationd_task izeneko egitura batean gordetzen dira:
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;
};
Name atributua zereginaren izena da. space_id atributua espazioaren identifikatzailea da. rm_index_id atributua tuplak ezabatuko diren indize esklusiboaren identifikatzailea da. it_index_id atributua tuplak zeharkatuko dituen indizearen identifikatzailea da. it_index_type atributua tuplak zeharkatuko dituen indize mota da. Filed_no atributua bizitza osoa duen tupla eremuaren zenbakia da. Scan_size atributua transakzio batean eskaneatzen den gehieneko tupla kopurua da. Scan_time atributua eskaneatu denbora osoa segundotan da.
Ez dugu kontuan hartuko argumentuak analizatzea. Lan neketsua baina sinplea da, eta horrekin liburutegiak lagunduko dizu
Analisirako erabiltzen diren funtzio guztien prototipoak zerrendatzen ditugu:
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);
Orain joan gaitezen garrantzitsuenera: espazioa saihestu eta tuplak ezabatzearen logika. Scan_size baino handiagoa ez den tupla-bloke bakoitza eskaneatu eta aldatzen da transakzio bakar baten arabera. Arrakasta bada, transakzio hau konprometituko da; errorea gertatzen bada, atzera egingo da. expirationd_iterate funtzioaren azken argumentua eskaneatzea hasten edo jarraitzen duen iteragailuaren erakuslea da. Iteratzaile hau barnean handitzen da errore bat gertatu arte, espazioa agortu arte edo ezin da prozesua aldez aurretik geldiarazi. expirationd_expired funtzioak tupla baten iraupena egiaztatzen du, expirationd_delete-k tupla bat ezabatzen du, expirationd_breakable-k aurrera egin behar dugun egiaztatzen du.
Expirationd_iterate funtzioaren kodea:
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;
}
Funtzio-kodea 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 funtzio-kodea:
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);
}
Funtzio-kodea 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;
}
Eskaera
Iturburu kodea hemen ikus dezakezu
Iturria: www.habr.com