Навиштани модули худамон барои tarantool

Навиштани модули худамон барои tarantool

Чанде пеш мо бо проблемаи тоза кардани лампахо дар фазохо дучор шуда будем тарантул. Тозакунӣ бояд на вақте ки tarantool аллакай аз хотира тамом шуд, балки пешакӣ ва бо басомади муайян оғоз карда шавад. Барои ин вазифа, tarantool дорои модули бо номи Луа навишта шудааст мухлат. Пас аз истифодаи ин модул дар муддати кӯтоҳ, мо фаҳмидем, ки он барои мо мувофиқ нест: аз сабаби тоза кардани миқдори зиёди маълумот, Луа дар GC овезон буд. Аз ин рӯ, мо дар бораи таҳияи модули худамон, ки ба охир мерасад, фикр мекардем ва умедворем, ки коде, ки бо забони модарии барномасозӣ навишта шудааст, мушкилоти моро ба таври беҳтарин ҳал мекунад.

Намунаи хуб барои мо модули tarantool буд ҳифзшуда. Муносибати дар он истифодашаванда ба он асос ёфтааст, ки дар фазо майдони алохида сохта мешавад, ки умри tuple, ба ибораи дигар, ttl-ро нишон медиҳад. Модул дар замина фосиларо скан мекунад, TTL-ро бо вақти ҷорӣ муқоиса мекунад ва тасмим мегирад, ки наворро нест кунед ё не. Рамзи модули memcached оддӣ ва шево аст, вале хеле умумӣ. Аввалан, он намуди индексеро, ки кофтуков ва нест карда мешавад, ба назар намегирад. Сониян, дар ҳар як гузариш ҳамаи кортҳо скан карда мешаванд, ки шумораи онҳо метавонад хеле зиёд бошад. Ва агар дар модули ба охиррасида масъалаи якум ҳал карда шуда бошад (индекси дарахт ба синфи алоҳида ҷудо карда шуд), пас ба дуюмаш то ҳол аҳамият намедиҳад. Ин се нукта интихобро ба манфиати навиштани рамзи шахсии ман пешакӣ муайян кард.

Шарҳи

Ҳуҷҷатҳои барои tarantool дорои хеле хуб дастур дар бораи чӣ гуна навиштани расмиёти захирашудаи худро дар C. Пеш аз ҳама, ман ба шумо тавсия медиҳам, ки бо он шинос шавед, то он иловаҳоро бо фармонҳо ва кодҳое, ки дар зер пайдо мешаванд, фаҳмед. Ба он низ эътибор додан лозим аст истинод ба объектҳое, ки ҳангоми навиштани модули пӯшидаи худ дастрасанд, яъне қуттии, нахи, шохиси и txn.

Биёед аз дур оғоз кунем ва бубинем, ки модули мӯҳлати истифодашуда аз берун чӣ гуна аст:

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

Ин мисол ҳангоми сканкунӣ айнан ҳамон модули мӯҳлати истифодашуда, ки дар Луа навишта шудааст, кор хоҳад кард. Далели аввалини функсияи оғоз номи беназири вазифа аст. Дуюм идентификатори фазо аст. Сеюм шохиси беназирест, ки тавассути он наворҳо нест карда мешаванд. Чаҳорум шохисест, ки тавассути он наворҳо тай карда мешаванд. Панҷум рақами майдони корбар бо давомнокии умр аст (рақамгузорӣ аз 1 оғоз мешавад, на 0!). Шашум ва ҳафтум танзимоти сканкунӣ мебошанд. 1024 шумораи максималии tuples мебошад, ки дар як транзаксия дидан мумкин аст. 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 меномем. Ин шохис набояд нодир бошад, бар хилофи шохиси ибтидоӣ. Гузариш аз рӯи индекси эксперт ва ҳазф аз рӯи ибтидоӣ анҷом дода мешавад. Мо дар хотир дорем, ки қаблан ҳарду танҳо бо истифода аз шохиси ибтидоӣ анҷом дода мешуданд.

Пас аз кори омодагӣ, мо функсияи оғозро бо далелҳои нав иҷро мекунем:

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

Реализация

Роҳи беҳтарини нақл кардани тамоми хусусиятҳои лоиҳа ин манбаи аслии он мебошад. код! Ҳамчун як қисми интишор, мо танҳо ба нуктаҳои муҳимтарин, яъне алгоритмҳои бурриши фазо тамаркуз хоҳем кард.

Далелҳое, ки мо ба усули оғоз мегузорем, дар сохторе бо номи 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 вақти пурраи скан дар сонияҳо мебошад.

Мо далелҳои таҳлилро баррасӣ намекунем. Ин кори душвор, вале оддӣ аст, ки дар он китобхона ба шумо кӯмак мекунад msgpuck. Мушкилот танҳо бо нишондиҳандаҳое ба миён омада метавонанд, ки аз Луа ҳамчун сохтори мураккаби додаҳо бо навъи mp_map дода мешаванд ва на истифода аз намудҳои оддии mp_bool, mp_double, mp_int, mp_uint ва mp_array. Аммо зарурати таҳлили тамоми индекс вуҷуд надорад. Ба шумо танҳо лозим аст, ки беназирии онро тафтиш кунед, намудро ҳисоб кунед ва идентификаторро истихроҷ кунед.

Мо прототипҳои ҳамаи функсияҳоро номбар мекунем, ки барои таҳлил истифода мешаванд:

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 мӯҳлати корбурдро месанҷад, 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;
}

Рамзи функсионалӣ 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;
}

Ариза

Шумо метавонед коди сарчашмаро дар дар ин ҷо!

Манбаъ: will.com

Илова Эзоҳ