å°ãåã«ãã¹ããŒã¹å
ã®ã¿ãã«ãã¯ãªãŒã³ã¢ãããããšããåé¡ã«çŽé¢ããŸããã
ç§ãã¡ã«ãšã£ãŠã®è¯ãäŸã¯ã次㮠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)
ç°¡åã«ããããã«ãlibcapped-expirationd.so ã©ã€ãã©ãªãé 眮ãããŠãããã£ã¬ã¯ããªã§ tarantool ãèµ·åããŸãã start ãš kill ãšãã XNUMX ã€ã®é¢æ°ãã©ã€ãã©ãªãããšã¯ã¹ããŒããããŸãã æåã®ã¹ãããã¯ãbox.schema.func.create ãš box.schema.user.grant ã䜿çšããŠãLua ãããããã®é¢æ°ãå©çšã§ããããã«ããããšã§ãã 次ã«ãã¿ãã«ã« XNUMX ã€ã®ãã£ãŒã«ãã®ã¿ãå«ãã¹ããŒã¹ãäœæããŸããXNUMX ã€ç®ã¯äžæã®èå¥åãXNUMX ã€ç®ã¯é»åã¡ãŒã«ãXNUMX ã€ç®ã¯ã¿ãã«ã®æå¹æéã§ãã æåã®ãã£ãŒã«ãã®äžã«ããªãŒ ã€ã³ããã¯ã¹ãæ§ç¯ããããããã©ã€ããªãšåŒã³ãŸãã 次ã«ããã€ãã£ã ã©ã€ãã©ãªãžã®æ¥ç¶ãªããžã§ã¯ããååŸããŸãã
æºåäœæ¥ãå®äºããããstart é¢æ°ãå®è¡ããŸãã
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 ã§æžãããæå¹æéåãã®ã¢ãžã¥ãŒã«ãšãŸã£ããåãããã«ã¹ãã£ã³äžã«åäœããŸãã start é¢æ°ã®æåã®åŒæ°ã¯ãã¿ã¹ã¯ã®äžæã®ååã§ãã 1 çªç®ã¯ã¹ããŒã¹èå¥åã§ãã 0 çªç®ã¯ãã¿ãã«ãåé€ããããã®äžæã®ã€ã³ããã¯ã¹ã§ãã 1024 çªç®ã¯ãã¿ãã«ã®èµ°æ»ã«äœ¿çšãããã€ã³ããã¯ã¹ã§ãã 3600 çªç®ã¯ãæå¹æéãæã€ã¿ãã« ãã£ãŒã«ãã®çªå·ã§ã (çªå·ä»ã㯠XNUMX ã§ã¯ãªã XNUMX ããå§ãŸããŸã)ã XNUMX çªç®ãš XNUMX çªç®ã¯ã¹ãã£ã³èšå®ã§ãã XNUMX ã¯ãXNUMX ã€ã®ãã©ã³ã¶ã¯ã·ã§ã³ã§è¡šç€ºã§ããã¿ãã«ã®æ倧æ°ã§ãã XNUMX â ãã« ã¹ãã£ã³æé (ç§)ã
ãã®äŸã§ã¯ãã¯ããŒã«ãšåé€ã«åãã€ã³ããã¯ã¹ã䜿çšããŠããããšã«æ³šæããŠãã ããã ãããããªãŒ ã€ã³ããã¯ã¹ã®å Žåãèµ°æ»ã¯å°ããããŒãã倧ããããŒãžå®è¡ãããŸãã ä»ã«ããã·ã¥ ã€ã³ããã¯ã¹ãªã©ãããå Žåãèµ°æ»ã¯ååãšããŠã©ã³ãã ãªé åºã§å®è¡ãããŸãã ãã¹ãŠã®ç©ºéã¿ãã«ã¯ XNUMX åã®ã¹ãã£ã³ã§ã¹ãã£ã³ãããŸãã
æå¹æéã 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'})
ã¯ããŒã«ã«å¥ã®ã€ã³ããã¯ã¹ã䜿çšããã XNUMX çªç®ã®äŸãèŠãŠã¿ãŸãããã
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)
ããã§ã¯ãããã€ãã®äŸå€ãé€ããŠããã¹ãŠæåã®äŸãšåãã§ãã XNUMX çªç®ã®ãã£ãŒã«ãã®äžã«ããªãŒ ã€ã³ããã¯ã¹ãæ§ç¯ããããã exp ãšåŒã³ãŸãã ãã®ã€ã³ããã¯ã¹ã¯ããã©ã€ããªãšåŒã°ããã€ã³ããã¯ã¹ãšã¯ç°ãªããäžæã§ããå¿ èŠã¯ãããŸããã èµ°æ»ã¯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 ç§ã®ã¿ãã«ãããã€ãæ®ã£ãŠããŸãã ããã«ãID 2ãã©ã€ãã¿ã€ã 1576421257 ã®ã¿ãã«ãã ID 3ãã©ã€ãã¿ã€ã 1576421287 ã®ã¿ãã«ã«ç§»åãããšãã«ã¹ãã£ã³ãåæ¢ããŸããã ã©ã€ãã¿ã€ã 1576421287 以äžã®ã¿ãã«ã¯ã次ã®é åºã«ããã¹ãã£ã³ãããŸããã§ããã exp ã€ã³ããã¯ã¹ããŒã ããã¯ç§ãã¡ãåœåéæããããšèããŠããç¯çŽã§ãã
ã¿ã¹ã¯ãåæ¢ããŸãããã
capped_connection:call('libcapped-expirationd.kill', {'indexed'})
å ·çŸå
ãããžã§ã¯ãã®ãã¹ãŠã®æ©èœã«ã€ããŠç¥ãæè¯ã®æ¹æ³ã¯ããã®å
ã®ãœãŒã¹ã§ãã
start ã¡ãœããã«æž¡ãåŒæ°ã¯ã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 å±æ§ã¯ã¿ã¹ã¯ã®ååã§ãã space_id å±æ§ã¯ã¹ããŒã¹èå¥åã§ãã rm_index_id å±æ§ã¯ãã¿ãã«ãåé€ãããäžæã®ã€ã³ããã¯ã¹ã®èå¥åã§ãã it_index_id å±æ§ã¯ãã¿ãã«ã®èµ°æ»ã«äœ¿çšãããã€ã³ããã¯ã¹ã®èå¥åã§ãã it_index_type å±æ§ã¯ãã¿ãã«ãèµ°æ»ãããã€ã³ããã¯ã¹ã®ã¿ã€ãã§ãã filed_no å±æ§ã¯ãæå¹æéãæã€ã¿ãã« ãã£ãŒã«ãã®çªå·ã§ãã scan_size å±æ§ã¯ãXNUMX ã€ã®ãã©ã³ã¶ã¯ã·ã§ã³ã§ã¹ãã£ã³ãããã¿ãã«ã®æ倧æ°ã§ãã 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 é¢æ°ã®æåŸã®åŒæ°ã¯ãã¹ãã£ã³ãéå§ãŸãã¯ç¶ç¶ãããå埩åãžã®ãã€ã³ã¿ã§ãã ãã®å埩åã¯ããšã©ãŒãçºçããããã¹ããŒã¹ããªããªãããäºåã«ããã»ã¹ãåæ¢ã§ããªããªããŸã§ãå éšçã«ã€ã³ã¯ãªã¡ã³ããããŸãã é¢æ°expired_expiredã¯ã¿ãã«ã®æå¹æéããã§ãã¯ããexpirationd_deleteã¯ã¿ãã«ãåé€ãã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;
}
é¢æ°ã³ãŒãexpired_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;
}
ã¢ããªã±ãŒã·ã§ã³
ãœãŒã¹ã³ãŒãã¯æ¬¡ã®å Žæã§è¡šç€ºã§ããŸãã
åºæïŒ habr.com