์ผ๋ง ์ ์ฐ๋ฆฌ๋ ๊ณต๊ฐ์ ํํ์ ์ ๋ฆฌํ๋ ๋ฌธ์ ์ ์ง๋ฉดํ์ต๋๋ค.
์ฐ๋ฆฌ์๊ฒ ์ข์ ์๋ ๋ค์๊ณผ ๊ฐ์ 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)๋ฅผ ๋ด๋ณด๋ ๋๋ค. ์ฒซ ๋ฒ์งธ ๋จ๊ณ๋ box.schema.func.create ๋ฐ box.schema.user.grant๋ฅผ ์ฌ์ฉํ์ฌ Lua์์ ์ด๋ฌํ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๋๋ก ๋ง๋๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฐ ๋ค์ ํํ์ ์ธ ๊ฐ์ ํ๋๋ง ํฌํจ๋๋ ๊ณต๊ฐ์ ๋ง๋ญ๋๋ค. ์ฒซ ๋ฒ์งธ๋ ๊ณ ์ ์๋ณ์, ๋ ๋ฒ์งธ๋ ์ด๋ฉ์ผ, ์ธ ๋ฒ์งธ๋ ํํ์ ์๋ช ์ ๋๋ค. ์ฒซ ๋ฒ์งธ ํ๋ ์์ ํธ๋ฆฌ ์ธ๋ฑ์ค๋ฅผ ๊ตฌ์ถํ๊ณ ์ด๋ฅผ ๊ธฐ๋ณธ์ด๋ผ๊ณ ๋ถ๋ฆ ๋๋ค. ๋ค์์ผ๋ก ๋ค์ดํฐ๋ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํ ์ฐ๊ฒฐ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
์ค๋น ์์ ์ด ๋๋๋ฉด ์์ ๊ธฐ๋ฅ์ ์คํํฉ๋๋ค.
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 โ ์ ์ฒด ์ค์บ ์๊ฐ(์ด)์ ๋๋ค.
์ด ์์์๋ ํฌ๋กค๋ง๊ณผ ์ญ์ ์ ๋์ผํ ์์ธ์ ์ฌ์ฉํฉ๋๋ค. ์ด๊ฒ์ด ํธ๋ฆฌ ์ธ๋ฑ์ค๋ผ๋ฉด ์์ ํค์์ ํฐ ํค๋ก ์ํ๊ฐ ์ํ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด ํด์ ์ธ๋ฑ์ค์ ๊ฐ์ ๋ค๋ฅธ ํญ๋ชฉ์ด ์์ผ๋ฉด ์ํ๋ ์ผ๋ฐ์ ์ผ๋ก ๋ฌด์์ ์์๋ก ์ํ๋ฉ๋๋ค. ๋ชจ๋ ๊ณต๊ฐ ํํ์ ํ ๋ฒ์ ์ค์บ์ผ๋ก ์ค์บ๋ฉ๋๋ค.
์๋ช ์ด 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๋ผ๊ณ ๋ถ๋ฆ ๋๋ค. ์ด ์ธ๋ฑ์ค๋ ๊ธฐ๋ณธ ์ธ๋ฑ์ค์ ๋ฌ๋ฆฌ ๊ณ ์ ํ ํ์๊ฐ ์์ต๋๋ค. ์ํ๋ exp ์ธ๋ฑ์ค๋ก ์ํ๋๊ณ ์ญ์ ๋ ๊ธฐ๋ณธ์ผ๋ก ์ํ๋ฉ๋๋ค. ์ด์ ์๋ ๋ ๊ฐ์ง ๋ชจ๋ ๊ธฐ๋ณธ ์ธ๋ฑ์ค๋ฅผ ์ฌ์ฉํด์๋ง ์ํ๋์๋ค๋ ๊ฒ์ ๊ธฐ์ตํฉ๋๋ค.
์ค๋น ์์ ์ด ๋๋๋ฉด ์ ์ธ์๋ฅผ ์ฌ์ฉํ์ฌ ์์ ํจ์๋ฅผ ์คํํฉ๋๋ค.
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 ์์ฑ์ ํ ํธ๋์ญ์ ์์ ์ค์บ๋๋ ์ต๋ ํํ ์์ ๋๋ค. 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๋ณด๋ค ํฌ์ง ์์ ๊ฐ ํํ ๋ธ๋ก์ ๋จ์ผ ํธ๋์ญ์ ์์ ์ค์บ๋๊ณ ์์ ๋ฉ๋๋ค. ์ฑ๊ณตํ๋ฉด ์ด ํธ๋์ญ์ ์ด ์ปค๋ฐ๋๊ณ , ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด ๋กค๋ฐฑ๋ฉ๋๋ค. ๋ง๋ฃ_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;
}
ํจ์ ์ฝ๋ ๋ง๋ฃ_๋ง๋ฃ:
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);
}
ํจ์ ์ฝ๋ ๋ง๋ฃ_ํด์ ๊ฐ๋ฅ:
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