د ټرینټول لپاره زموږ د خپل محدود شوي وخت پای ته رسیدو ماډل لیکل

د ټرینټول لپاره زموږ د خپل محدود شوي وخت پای ته رسیدو ماډل لیکل

یو څه وخت دمخه موږ په ځایونو کې د ټپلونو پاکولو ستونزې سره مخ وو تارنول. پاکول باید هغه وخت نه پیل شي کله چې ټرینټول دمخه له حافظې څخه تیر شوی و ، مګر دمخه او په یو ټاکلي فریکونسۍ کې. د دې کار لپاره، tarantool یو ماډل لري چې په Lua کې لیکل شوی ختمیدل. د لنډ وخت لپاره د دې ماډل کارولو وروسته، موږ پوهیږو چې دا زموږ لپاره مناسب نه و: د لوی مقدار معلوماتو د دوامداره پاکولو له امله، لوا په GC کې ځړول. له همدې امله، موږ د خپل محدود شوي وخت پای ته رسیدو ماډل رامینځته کولو په اړه فکر وکړ، په دې هیله چې په اصلي پروګرامینګ ژبه کې لیکل شوي کوډ به زموږ ستونزې په غوره توګه حل کړي.

زموږ لپاره یوه ښه بیلګه د ټرینټول ماډل و منل شوی. په دې کې کارول شوې تګلاره د دې حقیقت پراساس ده چې په ځای کې یو جلا ساحه رامینځته شوې ، کوم چې د ټیپل ژوند په ګوته کوي ، په بل عبارت ، ttl. په شالید کې ماډل ځای سکین کوي ​​، د اوسني وخت سره TTL پرتله کوي او پریکړه کوي چې ایا ټیپل حذف کړئ یا نه. د memcached ماډل کوډ ساده او ښکلی دی، مګر ډیر عام دی. لومړی، دا د شاخص ډول په پام کې نه نیسي چې کرول او حذف کیږي. دوهم ، په هر پاس کې ټول ټپلونه سکین شوي ، چې شمیر یې خورا لوی کیدی شي. او که په پای ته رسیدو ماډل کې لومړۍ ستونزه حل شوې وي (د ونې شاخص په جلا ټولګي کې جلا شوی و) ، نو دوهم یې لاهم پاملرنه نه ده کړې. دا درې ټکي زما د خپل کوډ لیکلو په ګټه انتخاب دمخه ټاکلی.

شرح

د ترنتول لپاره اسناد خورا ښه دي ښوونه په 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 د ټپلونو اعظمي شمیره ده چې په یوه معامله کې لیدل کیدی شي. 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 وایو. دا شاخص باید ځانګړی نه وي، برعکس د ابتدايي شاخص په نوم یادیږي. تګ راتګ به د exp index لخوا ترسره شي، او د ابتدايي له مخې حذف شي. موږ په یاد لرو چې مخکې دواړه یوازې د لومړني شاخص په کارولو سره ترسره شوي.

د چمتوالي کار وروسته، موږ د نوي دلیلونو سره د پیل فعالیت چلوو:

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 ثانیې به ژوند وکړي. برسېره پردې، سکین هغه وخت ودرول کله چې د 2 ID او 1576421257 ژوندانه سره د ټیپل څخه د 3 ID او 1576421287 ژوند کولو سره ټیپل ته حرکت کول. د 1576421287 یا ډیر عمر لرونکي ټیپلونه د ترتیب له امله سکین شوي ندي. د exp index کیلي. دا سپما ده چې موږ غوښتل په پیل کې ترلاسه کړو.

راځئ چې کار بند کړو:

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 خاصیت د شاخص ډول دی چې له مخې به یې ټپلونه تیریږي. file_no خاصیت د ژوند د وخت سره د ټپل ساحې شمیره ده. د سکین_سیز خاصیت د ټپلونو اعظمي شمیر دی چې په یوه معامله کې سکین شوي. د سکین_ټیم خاصیت په ثانیو کې د بشپړ سکین وخت دی.

موږ به د تحلیل دلیلونو ته پام ونه کړو. دا یو دردناک مګر ساده کار دی، چې کتابتون به تاسو سره مرسته وکړي msgpuck. ستونزې یوازې د شاخصونو سره رامینځته کیدی شي چې له Lua څخه د 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);

اوس راځئ چې ترټولو مهم شی ته لاړ شو - د ځای د تیرولو او د ټپلونو حذف کولو منطق. د ټیپلونو هر بلاک د سکین_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);
}

Expirationd_breakable فنکشن کوډ:

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

کاریال

تاسو کولی شئ د سرچینې کوډ وګورئ دلته!

سرچینه: www.habr.com

Add a comment