Manoratra ny maodely efa lany daty voasarona ho an'ny tarantool

Manoratra ny maodely efa lany daty voasarona ho an'ny tarantool

Fotoana vitsy lasa izay dia niatrika olana amin'ny fanadiovana ny tuples amin'ny habaka izahay tarantool. Ny fanadiovana dia tsy maintsy natomboka tsy rehefa lany ny fitadidiana ny tarantool, fa mialoha sy amin'ny matetika. Ho an'ity asa ity, ny tarantool dia manana module voasoratra amin'ny Lua antsoina lany. Rehefa avy nampiasa ity maody ity nandritra ny fotoana fohy, dia nahatsapa izahay fa tsy mety aminay: noho ny fanadiovana tsy tapaka ny angon-drakitra be dia be i Lua dia nihantona tao amin'ny GC. Noho izany, nieritreritra ny hamolavola ny maodely efa lany daty voafehy manokana izahay, nanantena fa hamaha ny olanay amin'ny fomba tsara indrindra ny kaody voasoratra amin'ny tenim-pirenena fandaharana.

Ohatra tsara ho antsika dia ny module tarantool antsoina memcached. Ny fomba fiasa ampiasaina ao dia mifototra amin'ny hoe misy saha misaraka noforonina ao amin'ny habaka, izay manondro ny androm-piainan'ny tuple, amin'ny teny hafa, ttl. Ny maody ao ambadika dia mijery ny habaka, mampitaha ny TTL amin'ny fotoana ankehitriny ary manapa-kevitra raha hamafa ilay tuple na tsia. Tsotra sy kanto ny code module memcached, saingy gΓ©nΓ©rique loatra. Voalohany, tsy miraharaha ny karazana fanondroana izay mandady sy mamafa. Faharoa, isaky ny pass dia scan daholo ny tuples, izay mety ho lehibe ny isan'izy ireo. Ary raha voavaha ny olana voalohany tao amin'ny maodely efa lany andro (nasaraka tamin'ny kilasy iray ny mari-pamantarana hazo), dia mbola tsy niraharaha ny faharoa. Ireo teboka telo ireo dia namaritra mialoha ny safidy hanohanana ny fanoratana ny code-ko manokana.

famaritana

Ny antontan-taratasy ho an'ny tarantool dia manana tena tsara fampianarana momba ny fomba hanoratana ny fomba fiasa voatahiry ao amin'ny C. Voalohany indrindra, manoro hevitra anao aho mba hahalalanao izany mba hahatakaranao ireo fampidirana misy baiko sy kaody izay hiseho etsy ambany. Tena ilaina koa ny mandinika Reference ho an'ny zavatra azo alaina rehefa manoratra ny maody misy anao manokana, izany hoe boaty, fibre, Fanondroana ΠΈ txn.

Andeha isika hanomboka avy lavitra ary hijery ny endriky ny maodely efa lany daty voasarona avy any ivelany:

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)

Ho fanatsorana dia manomboka ny tarantool ao amin'ny lahatahiry misy ny tranomboky libcapped-expirationd.so. Fampiasa roa no aondrana avy amin'ny tranomboky: manomboka sy mamono. Ny dingana voalohany dia ny fametrahana ireo fiasa ireo ho azo avy amin'i Lua amin'ny fampiasana box.schema.func.create sy box.schema.user.grant. Avy eo dia mamorona habaka izay ahitana saha telo ihany ny tuple: ny voalohany dia famantarana tokana, ny faharoa dia mailaka, ary ny fahatelo dia ny androm-piainan'ny tuple. Manangana tondro hazo eo an-tampon'ny saha voalohany isika ary miantso azy io ho voalohany. Avy eo dia mahazo ny zavatra mifandray amin'ny tranomboky teratany izahay.

Aorian'ny asa fanomanana dia araho ny asa fanombohana:

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

Ity ohatra ity dia hiasa mandritra ny fisavana mitovy tanteraka amin'ilay maodely lany daty, izay voasoratra amin'ny Lua. Ny tohan-kevitra voalohany amin'ny asa fanombohana dia ny anarana tokana amin'ny asa. Ny faharoa dia ny famantarana ny habaka. Ny fahatelo dia tondro tokana izay hamafa ny tuples. Ny fahefatra dia ny fanondroana izay handehanan'ny tuples. Ny fahadimy dia ny isan'ny saha tuple miaraka amin'ny androm-piainany (ny isa dia manomboka amin'ny 1 fa tsy 0!). Ny fahenina sy ny fahafito dia fikandrana scanning. 1024 no ambony indrindra isan'ny tuple azo jerena amin'ny fifanakalozana tokana. 3600 - fotoana scan feno ao anatin'ny segondra.

Mariho fa ny ohatra dia mampiasa tondro mitovy amin'ny mandady sy mamafa. Raha tondro hazo io, dia avy amin'ny lakile kely mankany amin'ny lehibe kokoa ny fandehanana. Raha misy hafa, ohatra, ny mari-pamantarana tenifototra, dia ny fandehanana dia atao amin'ny ankapobeny, amin'ny filaharana kisendrasendra. Ny tuples rehetra dia voazaha ao anaty scan iray.

Andao hampiditra tuple maromaro ao amin'ny habakabaka miaraka amin'ny fiainana 60 segondra:

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}

Andeha hojerentsika fa nahomby ny fampidirana:

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

Andeha avereno ny fifantenana aorian'ny 60+ segondra (manisa hatrany am-piandohan'ny fampidirana ny tuple voalohany) ary jereo fa efa vita ny maodely efa lany daty:

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

Atsaharo ny asa:

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

Andeha hojerentsika ny ohatra faharoa izay misy fanondroana misaraka ampiasaina amin'ny 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)

Ny zava-drehetra eto dia mitovy amin'ny ohatra voalohany, misy maningana vitsivitsy. Manangana tondro hazo eo an-tampon'ny saha fahatelo izahay ary miantso azy hoe exp. Tsy voatery ho tokana io fanondroana io, fa tsy toy ny fanondroana antsoina hoe voalohany. Ny traversal dia hatao amin'ny fanondroana exp, ary ny famafana amin'ny alΓ lan'ny voalohany. Tsaroantsika fa teo aloha dia samy natao tamin'ny fampiasana ny fanondro voalohany ihany.

Aorian'ny asa fanomanana dia mihazakazaka ny asa fanombohana miaraka amin'ny hevitra vaovao:

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

Andao hampiditra tuple maromaro ao amin'ny habaka indray miaraka amin'ny fiainana 60 segondra:

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}

Aorian'ny 30 segondra, amin'ny alΓ lan'ny fanoharana, dia hanampy tuple vitsivitsy hafa isika:

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}

Andeha hojerentsika fa nahomby ny fampidirana:

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

Andeha avereno ny fifantenana aorian'ny 60+ segondra (manisa hatrany am-piandohan'ny fampidirana ny tuple voalohany) ary jereo fa efa vita ny maodely efa lany daty:

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

Mbola misy tuples sisa tavela ao amin'ny habaka izay hanana 30 segondra eo ho eo sisa velona. Ankoatr'izay, nijanona ny scan rehefa nifindra avy amin'ny tuple misy ID 2 sy ny androm-piainan'ny 1576421257 mankany amin'ny tuple misy ID 3 ary ny androm-piainana 1576421287. ny fanalahidin'ny exp index. Izany no tahirim-bola tiana ho tratrarina tany am-boalohany.

Atsaharo ny asa:

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

fanatanterahana

Ny fomba tsara indrindra hilazana ny endri-javatra rehetra amin'ny tetikasa dia ny loharano voalohany. amin'ny! Ao anatin'ny famoahana dia tsy hifantoka afa-tsy amin'ireo teboka manan-danja indrindra isika, dia ny algorithm bypass space.

Ny hevitra ampitaina amin'ny fomba fanombohana dia voatahiry ao anaty rafitra antsoina hoe 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;
};

Ny anarana toetra dia ny anaran'ny asa. Ny toetran'ny space_id dia ny famantarana ny habaka. Ny toetra rm_index_id dia ny famantarana ny tondro tokana izay hamafa ny tuples. Ny toetran'ny it_index_id dia ny famantarana ny index izay handehanan'ny tuples. Ny toetran'ny it_index_type dia ny karazana index izay hizorana ny tuple. Ny toetran'ny filed_no dia ny isan'ny saha tuple miaraka amin'ny androm-piainany. Ny toetran'ny scan_size dia ny isan'ny tuple ambony indrindra voa-scan amin'ny fifanakalozana iray. Ny toetran'ny scan_time dia ny fotoana scan feno ao anatin'ny segondra.

Tsy handinika hevitra momba ny famakafakana isika. Asa mafy nefa tsotra ity, izay hanampy anao ny tranomboky msgpuck. Ny fahasahiranana dia mety hipoitra raha tsy amin'ny fanondroana izay ampitaina avy amin'i Lua ho firafitry ny angona saro-pady miaraka amin'ny karazana mp_map, fa tsy mampiasa ny karazana tsotra mp_bool, mp_double, mp_int, mp_uint ary mp_array. Saingy tsy ilaina ny manadihady ny index manontolo. Mila manamarina ny maha-tokana azy ianao, manao kajy ny karazana ary manala ny famantarana.

Tanisainay ny prototypes amin'ny fiasa rehetra ampiasaina amin'ny parsing:

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

Andeha isika hifindra amin'ny zava-dehibe indrindra - ny lojikan'ny fandalovana ny habaka sy ny famafana ny tuples. Ny bloc of tuples tsirairay izay tsy lehibe kokoa noho ny scan_size dia voazaha sy ovaina amin'ny fifanakalozana tokana. Raha mahomby dia vita io fifampiraharahana io; raha misy hadisoana dia averina. Ny tohan-kevitra farany amin'ny asa expirationd_iterate dia tondro mankany amin'ny iterator izay manomboka na mitohy ny scan. Ampitomboina ao anatiny ity mpanelanelana ity mandra-pahatongan'ny hadisoana, lany ny habaka, na tsy azo atao ny manakana ny dingana mialoha. Ny asa expirationd_expired dia manamarina ny androm-piainan'ny tuple, expirationd_delete dia mamafa tuple, expirationd_breakable manamarina raha mila mandroso isika.

Expirationd_iterate code function:

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

Kaody fiasa 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 code function:

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

Kaody fiasa mety ho lany daty:

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

fampiharana

Azonao atao ny mijery ny source code amin'ny eto!

Source: www.habr.com

Add a comment