Որոշ ժամանակ առաջ մենք բախվեցինք բացատներում բուկլետները մաքրելու խնդրին
Մեզ համար լավ օրինակ էր tarantool մոդուլը, որը կոչվում էր
Նկարագրություն
Փաստաթղթերը համար tarantool ունի շատ լավ
Եկեք սկսենք հեռվից և տեսնենք, թե ինչ տեսք ունի փակված ժամկետանց մոդուլը դրսից.
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)
Պարզության համար մենք գործարկում ենք tarantool այն գրացուցակում, որտեղ գտնվում է մեր libcapped-expirationd.so գրադարանը: Գրադարանից արտահանվում է երկու գործառույթ՝ սկսել և սպանել: Առաջին քայլը այս գործառույթները Lua-ից հասանելի դարձնելն է՝ օգտագործելով box.schema.func.create և box.schema.user.grant: Այնուհետև ստեղծեք մի տարածք, որի տուպլերը կպարունակեն ընդամենը երեք դաշտ. առաջինը եզակի նույնացուցիչ է, երկրորդը՝ էլ. Մենք ծառի ինդեքս ենք կառուցում առաջին դաշտի վերևում և այն անվանում ենք առաջնային: Հաջորդը մենք ստանում ենք կապի օբյեկտ մեր հայրենի գրադարանին:
Նախապատրաստական աշխատանքից հետո գործարկեք մեկնարկի գործառույթը.
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})
Այս օրինակը սկանավորման ժամանակ կաշխատի ճիշտ այնպես, ինչպես ժամկետանց մոդուլը, որը գրված է Lua-ով: Մեկնարկային ֆունկցիայի առաջին արգումենտը առաջադրանքի եզակի անվանումն է: Երկրորդը տարածության նույնացուցիչն է: Երրորդը եզակի ինդեքս է, որով կջնջվեն tuples-ները: Չորրորդը այն ցուցանիշն է, որով կանցնեն զույգերը: Հինգերորդը կյանքի տևողությամբ բազմակի դաշտի թիվն է (համարակալումը սկսվում է 1-ից, ոչ թե 0-ից): Վեցերորդ և յոթերորդը սկանավորման կարգավորումներն են: 1024-ը բազմակի առավելագույն քանակն է, որը կարելի է դիտել մեկ գործարքում: 3600 — ամբողջական սկանավորման ժամանակը վայրկյաններով:
Նկատի ունեցեք, որ օրինակը օգտագործում է նույն ցուցանիշը սողալու և ջնջելու համար: Եթե սա ծառի ինդեքս է, ապա անցումը կատարվում է փոքր բանալինից դեպի մեծը: Եթե կա որևէ այլ, օրինակ, հեշ ինդեքս, ապա անցումը կատարվում է, որպես կանոն, պատահական կարգով։ Բոլոր տիեզերական զույգերը սկանավորվում են մեկ սկանավորման մեջ:
Եկեք 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}
Եկեք ստուգենք, որ տեղադրումը հաջող է եղել.
tarantool> box.space.tester.index.primary:select()
---
- - [0, '[email protected]', 1576418976]
- [1, '[email protected]', 1576418976]
- [2, '[email protected]', 1576418976]
...
Եկեք կրկնենք ընտրությունը 60+ վայրկյանից հետո (հաշվելով առաջին կուպաժի տեղադրման սկզբից) և տեսնենք, որ փակված ժամկետանց մոդուլն արդեն մշակվել է.
tarantool> box.space.tester.index.primary:select()
---
- []
...
Եկեք դադարեցնենք առաջադրանքը.
capped_connection:call('libcapped-expirationd.kill', {'non-indexed'})
Եկեք նայենք երկրորդ օրինակին, որտեղ առանձին ինդեքս է օգտագործվում սահելու համար.
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)
Այստեղ ամեն ինչ նույնն է, ինչ առաջին օրինակում, մի քանի բացառություններով: Մենք երրորդ դաշտի վերևում կառուցում ենք ծառի ինդեքս և այն անվանում ենք exp: Պարտադիր չէ, որ այս ցուցանիշը եզակի լինի՝ ի տարբերություն առաջնային կոչվող ինդեքսի։ Անցումը կիրականացվի էքսպրես ինդեքսով, իսկ ջնջումը` առաջնային: Մենք հիշում ենք, որ նախկինում երկուսն էլ արվում էին միայն առաջնային ինդեքսով։
Նախապատրաստական աշխատանքից հետո մենք գործարկում ենք start ֆունկցիան նոր արգումենտներով.
capped_connection:call('libcapped-expirationd.start', {'indexed', box.space.tester.id, box.space.tester.index.primary, box.space.tester.index.exp, 3, 1024, 3600})
Եկեք նորից մի քանի դուպլիկներ տեղադրենք տարածության մեջ՝ 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}
30 վայրկյանից հետո, անալոգիայով, մենք կավելացնենք ևս մի քանի դուբլ.
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}
Եկեք ստուգենք, որ տեղադրումը հաջող է եղել.
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]
...
Եկեք կրկնենք ընտրությունը 60+ վայրկյանից հետո (հաշվելով առաջին կուպաժի տեղադրման սկզբից) և տեսնենք, որ փակված ժամկետանց մոդուլն արդեն մշակվել է.
tarantool> box.space.tester.index.primary:select()
---
- - [3, '[email protected]', 1576421287]
- [4, '[email protected]', 1576421287]
- [5, '[email protected]', 1576421287]
...
Տիեզերքում դեռևս մնացել են մի քանի դուբլներ, որոնց ապրելու համար կմնա ևս մոտ 30 վայրկյան: Ավելին, սկանավորումը դադարեց, երբ 2 ID-ով և 1576421257 տևողությամբ tuple-ից 3 ID-ով և 1576421287 տևողությամբ tuple տեղափոխվեց: exp ինդեքսի ստեղները: Սա այն խնայողությունն է, որին մենք ցանկանում էինք հասնել հենց սկզբից:
Եկեք դադարեցնենք առաջադրանքը.
capped_connection:call('libcapped-expirationd.kill', {'indexed'})
Իրականացման
Ծրագրի բոլոր հատկանիշների մասին պատմելու լավագույն միջոցը դրա սկզբնական աղբյուրն է:
Փաստարկները, որոնք մենք փոխանցում ենք սկզբնական մեթոդին, պահվում են 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;
};
Անվան հատկանիշը առաջադրանքի անունն է: Space_id հատկանիշը տարածության նույնացուցիչն է: rm_index_id հատկանիշը եզակի ինդեքսի նույնացուցիչն է, որով կջնջվեն բազմապատիկները: it_index_id հատկանիշն այն ինդեքսի նույնացուցիչն է, որով կանցնեն բազմակիները: It_index_type հատկանիշը ինդեքսի տեսակն է, որով կանցնեն տուպլերը: Filed_no հատկանիշը բազմակի դաշտի թիվն է կյանքի տևողությամբ: Scan_size հատկանիշը բազմակի առավելագույն քանակն է, որոնք սկանավորվում են մեկ գործարքում: Scan_time հատկանիշը սկանավորման ամբողջական ժամանակը վայրկյաններով է:
Մենք չենք քննարկի վերլուծական փաստարկները: Սա քրտնաջան, բայց պարզ աշխատանք է, որով գրադարանը կօգնի ձեզ
Մենք թվարկում ենք բոլոր գործառույթների նախատիպերը, որոնք օգտագործվում են վերլուծության համար.
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);
Հիմա անցնենք ամենագլխավորին` տարածությունը շրջանցելու և բազմոցները ջնջելու տրամաբանությանը: Scan_size-ից ոչ մեծ բազմությունների յուրաքանչյուր բլոկ սկանավորվում և փոփոխվում է մեկ գործարքի ներքո: Հաջողության դեպքում այս գործարքը կատարվում է, եթե սխալ է տեղի ունենում, այն հետ է վերադարձվում: Expirationd_iterate ֆունկցիայի վերջին արգումենտը ցուցիչ է դեպի կրկնող, որից սկսվում կամ շարունակվում է սկանավորումը: Այս կրկնողն ավելացվում է ներսում, մինչև սխալ տեղի ունենա, տարածքը սպառվի կամ հնարավոր չլինի նախապես դադարեցնել գործընթացը: Expirationd_expired ֆունկցիան ստուգում է tuple-ի կյանքը, expirationd_delete ջնջում է tuple, expirationd_breakable ստուգում է, թե արդյոք մենք պետք է առաջ շարժվենք:
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;
}
Գործառույթի կոդը 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 ֆունկցիայի կոդը.
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);
}
Գործառույթի կոդը 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;
}
App
Դուք կարող եք դիտել աղբյուրի կոդը այստեղ
Source: www.habr.com