Pagsulat sa among kaugalingon nga gitakpan nga expirationd module para sa tarantool

Pagsulat sa among kaugalingon nga gitakpan nga expirationd module para sa tarantool

Kaniadto nag-atubang kami sa problema sa paglimpyo sa mga tuple sa mga wanang tarantool. Ang pagpanglimpyo kinahanglang sugdan dili sa dihang ang tarantool nahutdan na sa memorya, apan sa abante ug sa usa ka piho nga frequency. Alang niini nga buluhaton, ang tarantool adunay module nga gisulat sa Lua nga gitawag pag-expire. Human magamit kini nga module sa mubo nga panahon, among naamgohan nga dili kini angay kanamo: tungod sa kanunay nga paglimpyo sa daghang mga datos, si Lua nagbitay sa GC. Busa, naghunahuna kami mahitungod sa paghimo sa among kaugalingon nga gitakpan nga expirationd module, naglaum nga ang code nga gisulat sa lumad nga programming language makasulbad sa among mga problema sa pinakamaayong paagi.

Usa ka maayong panig-ingnan alang kanamo mao ang tarantool module nga gitawag nagmcached. Ang pamaagi nga gigamit niini gibase sa kamatuoran nga ang usa ka bulag nga uma gihimo sa wanang, nga nagpaila sa tibuok kinabuhi sa tuple, sa laing pagkasulti, ttl. Ang module sa background nag-scan sa wanang, nagtandi sa TTL sa karon nga oras ug nagdesisyon kung tangtangon ang tuple o dili. Ang memcached module code kay simple ug elegante, pero generic kaayo. Una, wala kini magtagad sa matang sa indeks nga gi-crawl ug gitangtang. Ikaduha, sa matag pass ang tanan nga mga tuple gi-scan, ang gidaghanon niini mahimong dako kaayo. Ug kung sa natapos nga module ang una nga problema nasulbad (ang indeks sa kahoy gibulag sa usa ka lahi nga klase), nan ang ikaduha wala gihapon makadawat bisan unsang pagtagad. Kining tulo ka punto nagtino nang daan sa pagpili pabor sa pagsulat sa akong kaugalingong code.

paghulagway

Ang dokumentasyon alang sa tarantool adunay maayo kaayo tutorial bahin sa kung giunsa pagsulat ang imong gitipigan nga mga pamaagi sa C. Una sa tanan, gisugyot ko nga pamilyar ka niini aron masabtan ang mga pagsal-ot nga adunay mga mando ug code nga makita sa ubos. Angayan usab nga hatagan ug pagtagad pakisayran sa mga butang nga magamit sa pagsulat sa imong kaugalingon nga gitakpan nga module, nga mao kahon, fiber, index ΠΈ txn.

Magsugod kita gikan sa layo ug tan-awon kung unsa ang hitsura sa usa ka naka-cap nga expiration nga module gikan sa gawas:

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)

Alang sa kayano, gilusad namo ang tarantool sa direktoryo diin nahimutang ang among libcapped-expirationd.so library. Duha ka mga gimbuhaton ang gi-eksport gikan sa librarya: pagsugod ug pagpatay. Ang unang lakang mao ang paghimo niini nga mga function nga magamit gikan sa Lua gamit ang box.schema.func.create ug box.schema.user.grant. Dayon paghimo og usa ka luna kansang mga tuple adunay tulo lamang ka mga field: ang una usa ka talagsaon nga identifier, ang ikaduha mao ang email, ug ang ikatulo mao ang tibuok kinabuhi sa tuple. Nagtukod kami usa ka indeks sa kahoy sa ibabaw sa una nga uma ug gitawag kini nga panguna. Sunod makuha namon ang butang nga koneksyon sa among lumad nga librarya.

Pagkahuman sa trabaho sa pag-andam, pagdagan ang function sa pagsugod:

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})

Kini nga pananglitan magamit sa panahon sa pag-scan nga parehas sa na-expire nga module, nga gisulat sa Lua. Ang unang argumento sa pagsugod function mao ang talagsaon nga ngalan sa buluhaton. Ang ikaduha mao ang space identifier. Ang ikatulo usa ka talagsaon nga indeks diin ang mga tuple matangtang. Ang ikaupat mao ang index diin ang mga tuple maagian. Ang ikalima mao ang gidaghanon sa tuple field nga adunay tibuok kinabuhi (pagnumero magsugod gikan sa 1, dili 0!). Ang ikaunom ug ikapito mao ang mga setting sa pag-scan. Ang 1024 mao ang kinatas-ang gidaghanon sa mga tuple nga makita sa usa ka transaksyon. 3600 β€” bug-os nga oras sa pag-scan sa mga segundo.

Timan-i nga ang pananglitan naggamit sa parehas nga indeks alang sa pag-crawl ug pagtangtang. Kung kini usa ka indeks sa kahoy, nan ang pagbiyahe gihimo gikan sa gamay nga yawe hangtod sa labi ka dako. Kung adunay uban pa, pananglitan, hash index, nan ang traversal gihimo, ingon nga usa ka lagda, sa random order. Ang tanan nga mga tuple sa wanang gi-scan sa usa ka pag-scan.

Atong isulod ang daghang tuple sa wanang nga adunay tibuok kinabuhi nga 60 segundos:

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}

Atong susihon nga ang pagsal-ot malampuson:

tarantool> box.space.tester.index.primary:select()
---
- - [0, '[email protected]', 1576418976]
  - [1, '[email protected]', 1576418976]
  - [2, '[email protected]', 1576418976]
...

Atong sublion ang pagpili human sa 60+ ka segundos (pag-ihap gikan sa sinugdanan sa pagsal-ot sa unang tuple) ug tan-awa nga ang gitakpan nga expirationd module naproseso na:

tarantool> box.space.tester.index.primary:select()
---
  - []
...

Hunongon nato ang buluhaton:

capped_connection:call('libcapped-expirationd.kill', {'non-indexed'})

Atong tan-awon ang ikaduha nga pananglitan diin ang usa ka bulag nga indeks gigamit alang sa pag-crawl:

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)

Ang tanan dinhi parehas sa una nga pananglitan, nga adunay pipila nga mga eksepsiyon. Nagtukod kami usa ka indeks sa kahoy sa ibabaw sa ikatulo nga uma ug gitawag kini nga exp. Kini nga indeks dili kinahanglan nga talagsaon, dili sama sa indeks nga gitawag nga panguna. Ang traversal himuon pinaagi sa exp index, ug pagtangtang pinaagi sa primary. Nahinumdom kami nga kaniadto ang duha gihimo lamang gamit ang panguna nga indeks.

Pagkahuman sa buluhaton sa pag-andam, gipadagan namon ang pagsugod nga function nga adunay bag-ong mga argumento:

capped_connection:call('libcapped-expirationd.start', {'indexed', box.space.tester.id, box.space.tester.index.primary, box.space.tester.index.exp, 3, 1024, 3600})

Atong isulod ang daghang tuple sa wanang pag-usab nga adunay tibuok kinabuhi nga 60 segundos:

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}

Human sa 30 segundos, pinaagi sa analogy, magdugang kami og pipila pa ka tuple:

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}

Atong susihon nga ang pagsal-ot malampuson:

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]
...

Atong sublion ang pagpili human sa 60+ ka segundos (pag-ihap gikan sa sinugdanan sa pagsal-ot sa unang tuple) ug tan-awa nga ang gitakpan nga expirationd module naproseso na:

tarantool> box.space.tester.index.primary:select()
---
- - [3, '[email protected]', 1576421287]
  - [4, '[email protected]', 1576421287]
  - [5, '[email protected]', 1576421287]
...

Naa pay pipila ka tuple nga nahabilin sa wanang nga adunay mga 30 ka segundo pa nga mabuhi. Dugang pa, ang pag-scan mihunong sa dihang mibalhin gikan sa tuple nga adunay ID nga 2 ug tibuok kinabuhi nga 1576421257 ngadto sa tuple nga adunay ID nga 3 ug tibuok kinabuhi nga 1576421287. Ang mga tuple nga adunay tibuok kinabuhi nga 1576421287 o labaw pa wala ma-scan tungod sa pag-order sa ang exp index nga mga yawe. Kini ang savings nga gusto namong makab-ot sa sinugdanan pa lang.

Hunongon nato ang buluhaton:

capped_connection:call('libcapped-expirationd.kill', {'indexed'})

Pagpatuman

Ang pinakamaayong paagi sa pagsulti mahitungod sa tanang bahin sa usa ka proyekto mao ang orihinal nga tinubdan niini. code! Isip bahin sa publikasyon, magpunting lamang kami sa labing hinungdanon nga mga punto, nga mao, ang mga algorithm sa bypass sa wanang.

Ang mga argumento nga atong gipasa sa pamaagi sa pagsugod gitipigan sa usa ka istruktura nga gitawag 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;
};

Ang ngalan nga hiyas mao ang ngalan sa buluhaton. Ang space_id attribute mao ang space identifier. Ang rm_index_id attribute mao ang identifier sa talagsaong index diin ang mga tuple matangtang. Ang it_index_id attribute mao ang identifier sa index diin ang mga tuple maagian. Ang it_index_type nga attribute mao ang tipo sa index diin ang mga tuple maagian. Ang filed_no attribute mao ang gidaghanon sa tuple field nga adunay tibuok kinabuhi. Ang scan_size attribute mao ang pinakataas nga gidaghanon sa mga tuple nga gi-scan sa usa ka transaksyon. Ang kinaiya sa scan_time mao ang tibuok nga oras sa pag-scan sa mga segundo.

Dili nato tagdon ang pag-parse sa mga argumento. Kini usa ka makuti apan yano nga trabaho, diin ang librarya makatabang kanimo msgpuck. Ang mga kalisud mahimo ra nga motumaw sa mga indeks nga gipasa gikan sa Lua ingon usa ka komplikado nga istruktura sa datos nga adunay tipo nga mp_map, ug wala gigamit ang yano nga mga tipo nga mp_bool, mp_double, mp_int, mp_uint ug mp_array. Apan dili kinahanglan nga i-parse ang tibuuk nga indeks. Kinahanglan nimo nga susihon ang pagkatalagsaon niini, kuwentahon ang tipo ug kuhaa ang identifier.

Gilista namon ang mga prototype sa tanan nga mga gimbuhaton nga gigamit alang sa pag-parse:

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);

Karon magpadayon kita sa labing hinungdanon nga butang - ang lohika sa pag-bypass sa wanang ug pagtangtang sa mga tuple. Ang matag bloke sa tuple nga dili modako sa scan_size gi-scan ug giusab ubos sa usa ka transaksyon. Kung malampuson, kini nga transaksyon nahimo; kung adunay sayup, kini gibalik. Ang katapusang argumento sa expirationd_iterate function kay usa ka pointer sa iterator diin nagsugod o nagpadayon ang scanning. Kini nga iterator gidugangan sa sulod hangtod nga adunay usa ka sayup nga mahitabo, ang wanang mahurot, o dili posible nga pahunongon ang proseso sa una. Ang function nga expirationd_expired nagsusi sa tibuok kinabuhi sa usa ka tuple, expirationd_delete nagtangtang sa usa ka tuple, expirationd_breakable nagsusi kon kita kinahanglan nga magpadayon.

Expirationd_iterate function code:

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;
}

Function code 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 function code:

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);
}

Function code 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;
}

Paggamit

Mahimo nimong tan-awon ang source code sa dinhi!

Source: www.habr.com

Idugang sa usa ka comment