Pirms kÄda laika mÄs saskÄrÄmies ar telpu tÄ«rÄ«Å”anas problÄmu
Labs piemÄrs mums bija tarantool modulis ar nosaukumu
Apraksts
Tarantool dokumentÄcijai ir ļoti laba
SÄksim no tÄlienes un apskatÄ«sim, kÄ modulis ar ierobežotu derÄ«guma termiÅu izskatÄs no Ärpuses:
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)
VienkÄrŔības labad mÄs palaižam tarantool direktorijÄ, kurÄ atrodas mÅ«su bibliotÄka libcapped-expirationd.so. No bibliotÄkas tiek eksportÄtas divas funkcijas: start un kill. Pirmais solis ir padarÄ«t Ŕīs funkcijas pieejamas no Lua, izmantojot box.schema.func.create un box.schema.user.grant. PÄc tam izveidojiet atstarpi, kuras korteÅ¾Ä bÅ«s tikai trÄ«s lauki: pirmais ir unikÄls identifikators, otrais ir e-pasts, bet treÅ”ais ir kortedža kalpoÅ”anas laiks. MÄs izveidojam koka indeksu virs pirmÄ lauka un saucam to par primÄro. TÄlÄk mÄs iegÅ«stam savienojuma objektu ar mÅ«su dzimto bibliotÄku.
PÄc sagatavoÅ”anas darba palaidiet starta funkciju:
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})
Å is piemÄrs skenÄÅ”anas laikÄ darbosies tieÅ”i tÄpat kÄ modulis, kuram beidzies derÄ«guma termiÅÅ”, kas ir rakstÄ«ts Lua valodÄ. Pirmais sÄkuma funkcijas arguments ir uzdevuma unikÄlais nosaukums. Otrais ir telpas identifikators. TreÅ”ais ir unikÄls indekss, ar kuru tiks dzÄsti korteži. Ceturtais ir indekss, ar kuru tiks ŔķÄrsoti koreži. Piektais ir kortedža lauka numurs ar kalpoÅ”anas laiku (numerÄcija sÄkas no 1, nevis 0!). Sestais un septÄ«tais ir skenÄÅ”anas iestatÄ«jumi. 1024 ir maksimÄlais kortežu skaits, ko var skatÄ«t vienÄ darÄ«jumÄ. 3600 ā pilns skenÄÅ”anas laiks sekundÄs.
Å emiet vÄrÄ, ka piemÄrÄ tiek izmantots viens un tas pats indekss pÄrmeklÄÅ”anai un dzÄÅ”anai. Ja tas ir koka indekss, tad pÄrvietoÅ”anÄs tiek veikta no mazÄkÄs atslÄgas uz lielÄko. Ja ir kÄds cits, piemÄram, hash indekss, tad ŔķÄrsoÅ”ana parasti tiek veikta nejauÅ”Ä secÄ«bÄ. Visas telpas kopas tiek skenÄtas vienÄ skenÄÅ”anas reizÄ.
TelpÄ ievietosim vairÄkus koreÅ”us, kuru kalpoÅ”anas laiks ir 60 sekundes:
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}
PÄrbaudÄ«sim, vai ievietoÅ”ana bija veiksmÄ«ga:
tarantool> box.space.tester.index.primary:select()
---
- - [0, '[email protected]', 1576418976]
- [1, '[email protected]', 1576418976]
- [2, '[email protected]', 1576418976]
...
AtkÄrtosim atlasi pÄc 60+ sekundÄm (skaitot no pirmÄ kortedža ievietoÅ”anas sÄkuma) un pÄrbaudÄ«sim, vai modulis, kuram ir beidzies derÄ«guma termiÅÅ”, jau ir apstrÄdÄts:
tarantool> box.space.tester.index.primary:select()
---
- []
...
PÄrtrauksim uzdevumu:
capped_connection:call('libcapped-expirationd.kill', {'non-indexed'})
ApskatÄ«sim otru piemÄru, kur pÄrmeklÄÅ”anai tiek izmantots atseviŔķs rÄdÄ«tÄjs:
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)
Å eit viss ir tÄds pats kÄ pirmajÄ piemÄrÄ, ar dažiem izÅÄmumiem. MÄs izveidojam koka indeksu virs treÅ”Ä lauka un saucam to par exp. Å im indeksam nav jÄbÅ«t unikÄlam atŔķirÄ«bÄ no indeksa, ko sauc par primÄro. ApmeklÄÅ”ana tiks veikta pÄc exp indeksa, un dzÄÅ”ana tiks veikta ar primÄro. MÄs atceramies, ka iepriekÅ” abi tika veikti, izmantojot tikai primÄro indeksu.
PÄc sagatavoÅ”anas darba mÄs palaižam starta funkciju ar jauniem argumentiem:
capped_connection:call('libcapped-expirationd.start', {'indexed', box.space.tester.id, box.space.tester.index.primary, box.space.tester.index.exp, 3, 1024, 3600})
Atkal ievietosim telpÄ vairÄkas korteces ar 60 sekunžu kalpoÅ”anas laiku:
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}
PÄc 30 sekundÄm, pÄc analoÄ£ijas, mÄs pievienosim vÄl dažus virknes:
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}
PÄrbaudÄ«sim, vai ievietoÅ”ana bija veiksmÄ«ga:
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]
...
AtkÄrtosim atlasi pÄc 60+ sekundÄm (skaitot no pirmÄ kortedža ievietoÅ”anas sÄkuma) un pÄrbaudÄ«sim, vai modulis, kuram ir beidzies derÄ«guma termiÅÅ”, jau ir apstrÄdÄts:
tarantool> box.space.tester.index.primary:select()
---
- - [3, '[email protected]', 1576421287]
- [4, '[email protected]', 1576421287]
- [5, '[email protected]', 1576421287]
...
VietÄ joprojÄm ir palikuÅ”i daži elementi, kuriem atlikuÅ”as vÄl aptuveni 30 sekundes. TurklÄt skenÄÅ”ana tika pÄrtraukta, pÄrejot no kortedža ar ID 2 un kalpoÅ”anas laiku 1576421257 uz kortei ar ID 3 un kalpoÅ”anas laiku 1576421287. Korekti ar kalpoÅ”anas laiku 1576421287 vai vairÄk netika skenÄti exp indeksa atslÄgu secÄ«bas dÄļ. Tas ir ietaupÄ«jums, ko gribÄjÄm panÄkt paÅ”Ä sÄkumÄ.
PÄrtrauksim uzdevumu:
capped_connection:call('libcapped-expirationd.kill', {'indexed'})
IevieŔana
LabÄkais veids, kÄ pastÄstÄ«t par visÄm projekta iezÄ«mÄm, ir tÄ sÄkotnÄjais avots.
Argumenti, ko nododam sÄkuma metodei, tiek saglabÄti struktÅ«rÄ, ko sauc par 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;
};
Name atribÅ«ts ir uzdevuma nosaukums. AtribÅ«ts space_id ir telpas identifikators. AtribÅ«ts rm_index_id ir unikÄlÄ indeksa identifikators, ar kuru tiks dzÄsti korteži. AtribÅ«ts it_index_id ir indeksa identifikators, ar kuru tiks ŔķÄrsoti koreži. AtribÅ«ts it_index_type ir indeksa veids, ar kuru tiks ŔķÄrsoti korteži. AtribÅ«ts filed_no ir kortedža lauka numurs ar kalpoÅ”anas laiku. AtribÅ«ts scan_size ir maksimÄlais korežu skaits, kas tiek skenÄtas vienÄ darÄ«jumÄ. AtribÅ«ts scan_time ir pilns skenÄÅ”anas laiks sekundÄs.
MÄs neapsvÄrsim argumentu parsÄÅ”anu. Tas ir rÅ«pÄ«gs, bet vienkÄrÅ”s darbs, ar kuru bibliotÄka jums palÄ«dzÄs
MÄs uzskaitÄm visu parsÄÅ”anai izmantoto funkciju prototipus:
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);
Tagad pÄriesim pie vissvarÄ«gÄkÄs lietas - atstarpes apieÅ”anas un koreÅ”u dzÄÅ”anas loÄ£ikas. Katrs koreÅ”u bloks, kas nav lielÄks par scan_size, tiek skenÄts un modificÄts vienÄ transakcijÄ. Ja tas ir veiksmÄ«gs, Å”is darÄ«jums tiek veikts; ja rodas kļūda, tas tiek atcelts. PÄdÄjais arguments funkcijai expirationd_iterate ir rÄdÄ«tÄjs uz iteratoru, no kura sÄkas vai turpinÄs skenÄÅ”ana. Å is iterators tiek palielinÄts iekÅ”Äji, lÄ«dz rodas kļūda, beidzas vieta vai procesu nav iespÄjams apturÄt iepriekÅ”. Funkcija expirationd_expired pÄrbauda kortedža kalpoÅ”anas laiku, expirationd_delete dzÄÅ” koreÅ”u, expirationd_breakable pÄrbauda, āāvai mums ir jÄturpina.
Expirationd_iterate funkcijas kods:
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;
}
Funkcijas kods 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 funkcijas kods:
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);
}
Expirated_breakable funkcijas kods:
static bool
expirationd_breakable(struct expirationd_task *task)
{
return task->it_index_id != task->rm_index_id && task->it_index_type == ITER_GT;
}
Pieteikums
JÅ«s varat apskatÄ«t avota kodu vietnÄ
Avots: www.habr.com