A’ sgrìobhadh a’ mhodal crìochnachaidh againn fhèin airson tarantool

A’ sgrìobhadh a’ mhodal crìochnachaidh againn fhèin airson tarantool

O chionn ùine air ais bha an duilgheadas againn a bhith a’ glanadh tuples ann an àiteachan tarantool. Dh’ fheumadh glanadh a thòiseachadh chan ann nuair a bha tarantool a’ ruith a-mach à cuimhne mu thràth, ach ro-làimh agus aig tricead sònraichte. Airson na h-obrach seo, tha modal aig tarantool sgrìobhte ann an Lua ris an canar crìonadh. An dèidh a bhith a 'cleachdadh a' mhodail seo airson ùine ghoirid, thuig sinn nach robh e freagarrach dhuinn: mar thoradh air glanadh cunbhalach de mhòran dàta, bha Lua a 'crochadh anns an GC. Mar sin, smaoinich sinn mu bhith a’ leasachadh a’ mhodal crìochnachaidh againn fhèin le caiptean, an dòchas gun toireadh an còd a chaidh a sgrìobhadh ann an cànan prògramadh dùthchasach fuasgladh air na duilgheadasan againn anns an dòigh as fheàrr.

B’ e deagh eisimpleir dhuinn am modal tarantool ris an canar memcached. Tha an dòigh-obrach a thathar a 'cleachdadh ann stèidhichte air an fhìrinn gu bheil raon fa leth air a chruthachadh anns an àite, a tha a' comharrachadh beatha an tuple, ann am faclan eile, ttl. Bidh am modal air a’ chùl a’ sganadh an àite, a’ dèanamh coimeas eadar an TTL agus an ùine a th’ ann an-dràsta agus a’ co-dhùnadh am bu chòir an tuple a dhubhadh às no nach bu chòir. Tha còd modal memcached sìmplidh agus eireachdail, ach ro choitcheann. An toiseach, chan eil e a’ toirt aire don t-seòrsa clàr-amais a thathas a’ snàgail agus a’ sguabadh às. San dàrna h-àite, air gach pas tha na tuples uile air an sganadh, agus faodaidh an àireamh dhiubh a bhith gu math mòr. Agus ma chaidh a 'chiad dhuilgheadas fhuasgladh anns a' mhodal a dh'fhalbh (chaidh clàr-amais nan craobhan a roinn ann an clas air leth), cha d 'fhuair an dàrna fear aire sam bith fhathast. Bha na trì puingean sin ro-shuidhichte air an roghainn airson mo chòd fhìn a sgrìobhadh.

Tuairisgeul

Tha na sgrìobhainnean airson tarantool fìor mhath teagaisg mu mar a sgrìobhas tu na dòighean-obrach a tha air an stòradh agad ann an C. An toiseach, tha mi a’ moladh dhut eòlas fhaighinn air gus na cuir a-steach sin a thuigsinn le òrdughan agus còd a nochdas gu h-ìosal. Is fhiach aire a thoirt dha cuideachd iomradh ri nithean a tha rim faighinn nuair a bhios tu a’ sgrìobhadh am modal le caiptean agad fhèin, is e sin bogsa, freumhag, Clàr-ìnnse и txn.

Feuch an tòisich sinn bho chian agus coimhead air cò ris a tha modal crìochnachaidh le caip coltach bhon taobh a-muigh:

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)

Airson sìmplidh, bidh sinn a’ cur air bhog tarantool anns an eòlaire far a bheil an leabharlann libcapped-expirationd.so againn suidhichte. Tha dà ghnìomh air an às-mhalairt bhon leabharlann: tòiseachadh agus marbhadh. Is e a’ chiad cheum na gnìomhan sin a thoirt seachad bho Lua a’ cleachdadh box.schema.func.create agus box.schema.user.grant. An uairsin cruthaich àite anns nach bi ach trì raointean anns na tuples: tha a ’chiad fhear na aithnichear sònraichte, is e post-d an dàrna fear, agus is e an treas fear beatha an tuple. Bidh sinn a’ togail clàr-amais chraobhan air mullach a’ chiad achaidh agus ga ainmeachadh mar bhun-sgoil. An uairsin gheibh sinn an nì ceangail ris an leabharlann dhùthchasach againn.

Às deidh an obair ullachaidh, ruith an gnìomh tòiseachaidh:

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

Obraichidh an eisimpleir seo rè sganadh dìreach mar a tha am modal a dh’ fhalbh, a tha sgrìobhte ann an Lua. Is e a’ chiad argamaid don ghnìomh tòiseachaidh ainm sònraichte na h-obrach. Is e an dàrna fear an aithnichear fànais. Is e an treas fear clàr-amais sònraichte leis an tèid tuples a dhubhadh às. Is e an ceathramh clàr-amais leis an tèid na tuples a thionndadh. Is e an còigeamh àireamh an raon tuple le beatha (àireamhachadh a’ tòiseachadh bho 1, chan e 0!). Tha an t-siathamh agus an seachdamh suidheachadh sganaidh. Is e 1024 an àireamh as motha de thuples a chithear ann an aon ghnothach. 3600 - làn ùine scan ann an diogan.

Thoir an aire gu bheil an eisimpleir a’ cleachdadh an aon chlàr-amais airson a bhith a’ snàgail agus a’ cuir às. Mas e clàr craoibhe a tha seo, thèid an t-slighe tarsainn a dhèanamh bhon iuchair as lugha chun an tè as motha. Ma tha cuid eile ann, mar eisimpleir, clàr-amais hash, thèid an t-slighe tarsainn a dhèanamh, mar riaghailt, ann an òrdugh air thuaiream. Thèid a h-uile tuples fànais a sganadh ann an aon scan.

Nach cuir sinn grunn thuples a-steach don àite le beatha 60 diog:

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}

Feuch an dèan sinn cinnteach gun robh an cuir a-steach soirbheachail:

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

Nach dèan sinn an taghadh a-rithist às deidh 60+ diogan (a’ cunntadh bho thoiseach cuir a-steach a ’chiad tuple) agus chì sinn gu bheil am modal crìochnachaidh le caip air a phròiseasadh mu thràth:

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

Feuch an cuir sinn stad air an obair:

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

Bheir sinn sùil air dàrna eisimpleir far a bheil clàr-amais air leth air a chleachdadh airson an snàgadh:

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)

Tha a h-uile dad an seo mar a tha sa chiad eisimpleir, le beagan eisgeachdan. Bidh sinn a’ togail clàr-amais chraobhan air mullach an treas raon agus ga ainmeachadh mar exp. Chan fheum an clàr-amais seo a bhith gun samhail, eu-coltach ris a’ chlàr-amais ris an canar bun-sgoil. Thèid siubhal a dhèanamh le clàr-amais exp, agus cuir às leis a’ bhun-sgoil. Tha sinn a’ cuimhneachadh nach deach an dà chuid a dhèanamh roimhe seo ach a’ cleachdadh a’ phrìomh chlàr-amais.

Às deidh an obair ullachaidh, bidh sinn a’ ruith a’ ghnìomh tòiseachaidh le argamaidean ùra:

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

Nach cuir sinn grunn thuples a-steach don fhànais a-rithist le beatha 60 diog:

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}

Às deidh 30 diog, a rèir samhlachas, cuiridh sinn beagan tuples a bharrachd ris:

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}

Feuch an dèan sinn cinnteach gun robh an cuir a-steach soirbheachail:

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

Nach dèan sinn an taghadh a-rithist às deidh 60+ diogan (a’ cunntadh bho thoiseach cuir a-steach a ’chiad tuple) agus chì sinn gu bheil am modal crìochnachaidh le caip air a phròiseasadh mu thràth:

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

Tha cuid de thuples fhathast air fhàgail san àite aig am bi timcheall air 30 diog a bharrachd airson a bhith beò. A bharrachd air an sin, stad an scan nuair a ghluais e bho thuple le ID de 2 agus beatha 1576421257 gu tuple le ID de 3 agus beatha 1576421287. Cha deach tuples le beatha 1576421287 no barrachd a sganadh ri linn òrdugh na h-iuchraichean clàr-amais exp. Is e seo na sàbhalaidhean a bha sinn airson a choileanadh aig an fhìor thoiseach.

Feuch an cuir sinn stad air an obair:

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

Реализация

Is e an dòigh as fheàrr air innse mu fheartan pròiseict gu lèir a thùs. còd! Mar phàirt den fhoillseachadh, cha chuir sinn fòcas ach air na puingean as cudromaiche, is e sin, algorithms seach-rathad fànais.

Tha na h-argamaidean a bheir sinn don dòigh tòiseachaidh air an stòradh ann an structar ris an canar 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;
};

Is e am feart ainm ainm na h-obrach. Is e am feart space_id an aithnichear fànais. Is e am feart rm_index_id aithnichear a’ chlàr-amais shònraichte leis an tèid tuples a sguabadh às. Is e am feart it_index_id aithnichear a’ chlàr-amais leis an tèid tuples a thrasnadh. Is e am feart it_index_type an seòrsa clàr-amais leis an tèid tuples a thionndadh. Is e am feart filed_no an àireamh den raon tuple le beatha. Is e am feart scan_size an àireamh as motha de thuples a thèid a sganadh ann an aon ghnothach. Is e am feart scan_time an ùine sgrùdaidh iomlan ann an diogan.

Cha bheachdaich sinn air argamaidean a pharsadh. Is e obair mhionaideach ach sìmplidh a tha seo, leis an cuidich an leabharlann thu msgpuck. Chan urrainn do dhuilgheadasan èirigh ach le clàran-amais a thèid a thoirt seachad bho Lua mar structar dàta iom-fhillte leis an t-seòrsa mp_map, agus gun a bhith a’ cleachdadh nan seòrsaichean sìmplidh mp_bool, mp_double, mp_int, mp_uint agus mp_array. Ach chan eil feum air an clàr-amais gu lèir a pharsadh. Feumaidh tu dìreach sgrùdadh a dhèanamh air cho sònraichte ‘s a tha e, obrachadh a-mach an seòrsa agus an aithnichear a thoirt a-mach.

Bidh sinn a’ liostadh na prototypes de gach gnìomh a thathas a’ cleachdadh airson parsadh:

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

A-nis gluaisidh sinn air adhart chun rud as cudromaiche - an loidsig airson a bhith a 'seachnadh àite agus a' sguabadh às tuples. Tha gach bloc de thuples nach eil nas motha na scan_size air a sganadh agus air atharrachadh fo aon ghnothach. Ma shoirbhicheas leis, tha an gnothach seo dealasach; ma thachras mearachd, thèid a thoirt air ais. Tha an argamaid mu dheireadh don ghnìomh expirationd_iterate na chomharra don neach-aithris às a bheil an sganadh a’ tòiseachadh no a’ leantainn. Tha an iterator seo air a mheudachadh a-staigh gus an tachair mearachd, ruithidh an t-àite a-mach, no gus nach bi e comasach stad a chuir air a’ phròiseas ro-làimh. Bidh an gnìomh expirationd_expired a’ sgrùdadh beatha tuple, bidh expirationd_delete a’ cuir às do thuple, bidh expirationd_breakable a’ dearbhadh am feum sinn gluasad air adhart.

Còd gnìomh 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;
}

Còd gnìomh 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 còd gnìomh:

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

Còd gnìomh 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;
}

Iarrtas

Chì thu an còd tùsail aig an seo!

Source: www.habr.com

Cuir beachd ann