Ag scríobh ár modúl dul in éag teorainn féin le haghaidh tarantool

Ag scríobh ár modúl dul in éag teorainn féin le haghaidh tarantool

Tamall ó shin bhí muid ag tabhairt aghaidhe ar an bhfadhb a bhaineann le tuples a ghlanadh i spásanna tarantool. B’éigean an glantachán a thosú ní nuair a bhí tarantool ag rith as cuimhne cheana féin, ach roimh ré agus ag minicíocht áirithe. Don tasc seo, tá modúl scríofa ag tarantool i Lua ar a dtugtar éag. Tar éis an modúl seo a úsáid ar feadh tamaill ghearr, thuig muid nach raibh sé oiriúnach dúinn: mar gheall ar ghlanadh leanúnach ar mhéideanna móra sonraí, crochadh Lua sa GC. Mar sin, smaoiníomar ar ár modúl éagtha teorainn féin a fhorbairt, ag súil go réiteodh an cód scríofa i dteanga ríomhchlárúcháin dhúchais ár bhfadhbanna ar an mbealach is fearr is féidir.

Sampla maith dúinn ab ea an modúl tarantool ar a dtugtar memcached. Tá an cur chuige a úsáidtear ann bunaithe ar an bhfíric go gcruthaítear réimse ar leith sa spás, rud a léiríonn saolré an tuple, i bhfocail eile, ttl. Déanann an modúl sa chúlra an spás a scanadh, déanann sé comparáid idir an TTL agus an t-am atá ann faoi láthair agus cinneann an scriostar an tuple nó nach scriosfar. Tá cód an mhodúil memcached simplí agus galánta, ach ró-chineálach. Ar an gcéad dul síos, ní chuireann sé san áireamh an cineál innéacs atá á crawling agus a scriosadh. Ar an dara dul síos, déantar na tuples go léir a scanadh ar gach pas, agus is féidir leis an líon a bheith sách mór. Agus más rud é sa mhodúl imithe in éag a réitíodh an chéad fhadhb (roinneadh an t-innéacs crann i rang ar leith), ansin níor tugadh aird ar an dara ceann fós. Rinne na trí phointe seo réamhchinneadh ar an rogha i bhfabhar mo chód féin a scríobh.

Cur síos

Tá an doiciméadú le haghaidh tarantool an-mhaith teagaisc faoi ​​conas do nósanna imeachta stóráilte a scríobh i C. Ar an gcéad dul síos, molaim duit dul i dtaithí air chun na hionchuir sin a thuiscint le horduithe agus cód a bheidh le feiceáil thíos. Is fiú aird a thabhairt freisin ar tagairt le rudaí atá ar fáil agus do mhodúl caipínithe féin á scríobh, eadhon bosca, snáithín, innéacs и txn.

Tosaímid ó chian agus breathnaímis ar an gcuma atá ar mhodúl caite a bhfuil caipín air ón taobh amuigh:

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)

Ar mhaithe le simplíocht, seolann muid tarantool san eolaire ina bhfuil ár leabharlann libcapped-expirationd.so suite. Déantar dhá fheidhm a onnmhairiú ón leabharlann: tosú agus marú. Is é an chéad chéim na feidhmeanna seo a chur ar fáil ó Lua ag baint úsáide as box.schema.func.create agus box.schema.user.grant. Ansin cruthaigh spás nach mbeidh ach trí réimse sna tuples: is aitheantóir uathúil é an chéad cheann, is ríomhphost é an dara ceann, agus is é an tríú saolré an tuple. Tógann muid innéacs crann ar bharr an chéad réimse agus tugtar príomhúil air. Ansin gheobhaidh muid an réad nasctha lenár leabharlann dúchais.

Tar éis na hoibre ullmhúcháin, rith an fheidhm tosaithe:

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

Oibreoidh an sampla seo le linn scanadh díreach mar an gcéanna leis an modúl imithe in éag, atá scríofa i Lua. Is é an chéad argóint leis an bhfeidhm tosaithe ainm uathúil an taisc. Is é an dara ceann an t-aitheantóir spáis. Is é an tríú innéacs uathúil trína scriosfar tuples. Is é an ceathrú ceann an t-innéacs trína dtrasnófar na tuples. Is é an cúigiú líon an réimse tuple le saolré (tosaíonn an uimhriú ó 1, ní 0!). Is socruithe scanadh iad an séú agus an seachtú. Is é 1024 an t-uaslíon tuples is féidir a fheiceáil in aon idirbheart amháin. 3600 — scanadh iomlán i soicindí.

Tabhair faoi deara go n-úsáideann an sampla an t-innéacs céanna le haghaidh crawling agus scriosadh. Más innéacs crann é seo, déantar an trasnú ón eochair níos lú go dtí an ceann is mó. Má tá innéacs hash éigin eile ann, mar shampla, déantar an trasnú, mar riail, in ord randamach. Déantar gach tuple spáis a scanadh in aon scanadh amháin.

Cuirimis roinnt tuples isteach sa spás le saolré 60 soicind:

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}

Déanaimis seiceáil ar éirigh leis an gcur isteach:

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

Déanaimis an roghnú arís tar éis 60+ soicind (ag comhaireamh ó thús chur isteach an chéad tuple) agus féachfaimid go bhfuil an modúl teorantach caite próiseáilte cheana féin:

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

Stopaimis an tasc:

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

Breathnaímid ar an dara sampla ina n-úsáidtear innéacs ar leith don chraobhscaoileadh:

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)

Tá gach rud anseo mar an gcéanna leis an gcéad sampla, le roinnt eisceachtaí. Tógaimid innéacs crann ar bharr an tríú réimse agus tugaimid exp. Ní gá go mbeadh an t-innéacs seo uathúil, murab ionann agus an t-innéacs ar a dtugtar bunscoile. Déanfar trasnú trí innéacs exp, agus déanfar é a scriosadh de réir bunscoile. Cuimhnímid nach ndearnadh an dá cheann roimhe seo ach ag baint úsáide as an innéacs bunscoile.

Tar éis na hoibre ullmhúcháin, reáchtálaimid an fheidhm tosaithe le hargóintí nua:

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

Cuirimis roinnt tuples isteach sa spás arís le saolré 60 soicind:

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}

Tar éis 30 soicind, de réir analaí, cuirfimid cúpla tuple eile leis:

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}

Déanaimis seiceáil ar éirigh leis an gcur isteach:

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

Déanaimis an roghnú arís tar éis 60+ soicind (ag comhaireamh ó thús chur isteach an chéad tuple) agus féachfaimid go bhfuil an modúl teorantach caite próiseáilte cheana féin:

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

Tá roinnt tuples fós fágtha sa spás a mbeidh thart ar 30 soicind eile acu le maireachtáil. Ina theannta sin, stop an scanadh nuair a aistríodh ó thuple le haitheantas de 2 agus saolré 1576421257 go tuple le ID de 3 agus saolré 1576421287. Níor scanadh tuples le saolré 1576421287 nó níos mó mar gheall ar ordú na na heochracha innéacs exp. Seo é an coigilteas a theastaigh uainn a bhaint amach ag an tús.

Stopaimis an tasc:

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

Cur i bhFeidhm

Is é an bealach is fearr le insint faoi ghnéithe uile an tionscadail ná a fhoinse bunaidh. код! Mar chuid den fhoilseachán, díreoimid ach ar na pointí is tábhachtaí, eadhon, halgartaim sheachbhóthar spáis.

Stóráiltear na hargóintí a sheolaimid chuig an modh tosaithe i struchtúr ar a dtugtar 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 é an tréith ainm an t-ainm ar an tasc. Is é an aitreabúid space_id an t-aitheantóir spáis. Is é an aitreabúid rm_index_id aitheantóir an innéacs uathúil trína scriosfar tuples. Is é an aitreabúid it_index_id aitheantóir an innéacs trína dtrasnófar tuples. Is é an aitreabúid it_index_type an cineál innéacs trína dtrasnófar tuples. Is é an tréith filed_no líon an réimse tuple le saolré. Is é an aitreabúid scan_size an t-uaslíon tuples a scanadh in aon idirbheart amháin. Is é an aitreabúid scan_time an t-am scanadh iomlán i soicindí.

Ní bhreithneoidh muid argóintí parsála. Is obair dhian ach simplí é seo, agus cabhróidh an leabharlann leat msgpuck. Ní féidir le deacrachtaí teacht chun cinn ach amháin le hinnéacsanna a chuirtear ar aghaidh ó Lua mar struchtúr sonraí casta leis an gcineál mp_map, agus gan úsáid a bhaint as na cineálacha simplí mp_bool, mp_double, mp_int, mp_uint agus mp_array. Ach ní gá an t-innéacs iomlán a pharsáil. Ní mór duit ach a uathúlacht a sheiceáil, an cineál a ríomh agus an t-aitheantóir a bhaint as.

Déanaimid liosta de na fréamhshamhlacha de na feidhmeanna go léir a úsáidtear le haghaidh parsála:

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

Anois, a ligean ar bogadh ar aghaidh go dtí an rud is tábhachtaí - an loighic seachaint spáis agus scriosadh tuples. Déantar gach bloc tuples nach mó ná scan_size a scanadh agus a mhodhnú faoi aon idirbheart amháin. Má éiríonn leis, déantar an t-idirbheart seo; má tharlaíonn earráid, cuirfear ar ais é. Is í an argóint dheireanach don fheidhm expirationd_iterate ná pointeoir don atrialltóir óna dtosaíonn an scanadh nó óna leanann sé ar aghaidh. Déantar an t-iterator seo a mhéadú go hinmheánach go dtí go dtarlaíonn earráid, ritheann an spás amach, nó ní féidir an próiseas a stopadh roimh ré. Seiceálann an fheidhm expirationd_expired saolré tuple, scriosann expirationd_delete tuple, seiceálann expirationd_breakable an gá dúinn dul ar aghaidh.

Cód feidhme_iterate_in éag:

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 feidhme in éag_in éag:

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

In éag_scrios cód feidhme:

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 feidhme in éag_bhriste:

static bool
expirationd_breakable(struct expirationd_task *task)
{
  return task->it_index_id != task->rm_index_id && task->it_index_type == ITER_GT;
}

Iarratas

Is féidir leat an cód foinse a fheiceáil ag anseo!

Foinse: will.com

Add a comment