ለ tarantool የራሳችንን የተሸፈነ ጊዜው ያለፈበት ሞጁል በመጻፍ ላይ

ለ tarantool የራሳችንን የተሸፈነ ጊዜው ያለፈበት ሞጁል በመጻፍ ላይ

ከተወሰነ ጊዜ በፊት በቦታዎች ውስጥ ቱቦዎችን የማጽዳት ችግር አጋጥሞናል tarantool. ጽዳት መጀመር ያለበት tarantool ቀድሞውኑ የማስታወስ ችሎታ ሲያልቅ ሳይሆን አስቀድሞ እና በተወሰነ ድግግሞሽ ነው። ለዚህ ተግባር፣ tarantool የሚባል በሉአ የተጻፈ ሞጁል አለው። የማለቂያ ጊዜ. ይህንን ሞጁል ለአጭር ጊዜ ከተጠቀምን በኋላ ለእኛ ተስማሚ እንዳልሆነ ተገነዘብን: ብዙ መጠን ያለው መረጃን በተከታታይ በማጽዳት ምክንያት ሉአ በጂሲ ውስጥ ተንጠልጥሏል. ስለዚህ፣ በአፍ መፍቻ ቋንቋ የተጻፈው ኮድ ችግሮቻችንን በተሻለ መንገድ እንደሚፈታልን ተስፋ በማድረግ የራሳችንን የታሸገ ጊዜ ያለፈበት ሞጁል ለማዘጋጀት አሰብን።

ለእኛ ጥሩ ምሳሌ የሚጠራው የ tarantool ሞጁል ነበር። memcached. በውስጡ ጥቅም ላይ የዋለው አቀራረብ በቦታ ውስጥ የተለየ መስክ በመፈጠሩ ላይ የተመሰረተ ነው, ይህም የ tuple የህይወት ዘመንን ያመለክታል, በሌላ አነጋገር, tl. ከበስተጀርባ ያለው ሞጁል ቦታውን ይቃኛል, TTL ን ከአሁኑ ጊዜ ጋር ያወዳድራል እና ቱፕል ለመሰረዝ ወይም ላለመሰረዝ ይወስናል. የተቀረጸው ሞጁል ኮድ ቀላል እና የሚያምር ነው፣ ግን በጣም አጠቃላይ ነው። በመጀመሪያ, እየተጎተተ እና እየተሰረዘ ያለውን የመረጃ ጠቋሚ አይነት ግምት ውስጥ አያስገባም. በሁለተኛ ደረጃ, በእያንዳንዱ ማለፊያ ላይ ሁሉም ቱፕሎች ይቃኛሉ, ቁጥራቸው በጣም ትልቅ ሊሆን ይችላል. እና ጊዜው ካለፈበት ሞጁል ውስጥ የመጀመሪያው ችግር ከተፈታ (የዛፉ ኢንዴክስ ወደ ተለየ ክፍል ተከፍሏል) ፣ ከዚያ ሁለተኛው አሁንም ምንም ትኩረት አላገኘም። እነዚህ ሶስት ነጥቦች የራሴን ኮድ ለመጻፍ ምርጫውን አስቀድመው ወስነዋል።

መግለጫ

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

ለቀላልነት፣ የእኛ libcapped-expirationd.so ላይብረሪ በሚገኝበት ማውጫ ውስጥ tarantool ን እናስጀምራለን። ሁለት ተግባራት ከቤተ-መጽሐፍት ወደ ውጭ ይላካሉ: ይጀምሩ እና ይገድሉ. የመጀመሪያው እርምጃ box.schema.func.create እና box.schema.user.grant በመጠቀም እነዚህን ተግባራት ከሉአ ማግኘት ነው። ከዚያ ቱፕልዎቹ ሶስት መስኮችን ብቻ የሚይዙበት ቦታ ይፍጠሩ የመጀመሪያው ልዩ መለያ ነው ፣ ሁለተኛው ኢሜል ነው ፣ እና ሶስተኛው የ tuple የህይወት ዘመን ነው። በመጀመሪያው መስክ ላይ የዛፍ ኢንዴክስ እንገነባለን እና የመጀመሪያ ደረጃ ብለን እንጠራዋለን. በመቀጠል ግንኙነቱን ወደ ቤተኛ ቤተ-መጽሐፍታችን እናገኛለን።

ከዝግጅት ስራው በኋላ የመነሻ ተግባሩን ያሂዱ-

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

ይህ ምሳሌ በሉአ ከተጻፈው ጊዜው ያለፈበት ሞጁል በሚቃኝበት ጊዜ ይሰራል። ለጀማሪ ተግባር የመጀመሪያው ነጋሪ እሴት የተግባሩ ልዩ ስም ነው። ሁለተኛው የቦታ መለያ ነው። ሦስተኛው tuples የሚሰረዙበት ልዩ መረጃ ጠቋሚ ነው። አራተኛው ቱፕልስ የሚያልፍበት መረጃ ጠቋሚ ነው. አምስተኛው የህይወት ዘመን ያለው የ tuple መስክ ቁጥር ነው (ቁጥር የሚጀምረው ከ 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)

እዚህ ያለው ሁሉም ነገር ከመጀመሪያው ምሳሌ ጋር ተመሳሳይ ነው, ከጥቂቶች በስተቀር. በሦስተኛው መስክ ላይ የዛፍ ኢንዴክስ እንሠራለን እና ኤክስፕሽን እንጠራዋለን. ይህ ኢንዴክስ የመጀመሪያ ደረጃ ተብሎ ከሚጠራው ኢንዴክስ በተለየ ልዩ መሆን የለበትም። መሻገር የሚከናወነው በኤክስፕ ኢንዴክስ፣ እና ስረዛ በቀዳሚ ነው። ቀደም ሲል ሁለቱም የተከናወኑት ዋናውን ኢንዴክስ በመጠቀም ብቻ እንደነበር እናስታውሳለን.

ከዝግጅት ስራው በኋላ የጅምር ተግባሩን በአዲስ ነጋሪ እሴቶች እንሰራለን-

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 መታወቂያ ካለው ቱፕል እና 1576421257 ከ tuple ወደ 3 መታወቂያ እና የህይወት ዘመኑ 1576421287 ሲንቀሳቀስ ቅኝቱ ቆመ። የኤክስፕ ኢንዴክስ ቁልፎች. ይህ ገና መጀመሪያ ላይ ማግኘት የምንፈልገው ቁጠባ ነው።

ስራውን እናቁም፡-

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 አይነታ tuples የሚሰረዙበት ልዩ መረጃ ጠቋሚ መለያ ነው። የ it_index_id ባህሪው ቱፕልስ የሚያልፍበት የመረጃ ጠቋሚ መለያ ነው። የ it_index_አይነት ባህሪው ቱፕልስ የሚያልፍበት የመረጃ ጠቋሚ አይነት ነው። የፋይል_ኖ አይነታ እድሜ ልክ ያለው የ tuple መስክ ቁጥር ነው። የቃኝ_መጠን ባህሪ በአንድ ግብይት ውስጥ የሚቃኙ ከፍተኛው የቱፕሎች ብዛት ነው። የፍተሻ_ጊዜ ባህሪ በሰከንዶች ውስጥ ሙሉ የፍተሻ ጊዜ ነው።

ክርክሮችን መተንተን አናስብም። ይህ በጣም አድካሚ ግን ቀላል ስራ ነው፣ እሱም ቤተ መፃህፍቱ የሚረዳዎት 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);

አሁን ወደ በጣም አስፈላጊው ነገር እንሸጋገር - ቦታን የማለፍ እና ቱፕሎችን የመሰረዝ አመክንዮ። ከስካን_መጠን የማይበልጥ እያንዳንዱ የቱፕል ግንባታ በአንድ ግብይት ይቃኛል እና ተስተካክሏል። ከተሳካ ይህ ግብይት ተፈጽሟል፤ ስህተት ከተፈጠረ ተመልሶ ተንከባሎ ነው። የመጨረሻው መከራከሪያ ጊዜው ያለፈበት_ኢቴሬትድ ተግባር ፍተሻው የሚጀመርበት ወይም የሚቀጥልበት የድጋሚ ጠቋሚ ነው። ይህ ተደጋጋሚ ስህተት እስኪፈጠር ድረስ፣ ቦታው እስኪያልቅ ወይም ሂደቱን ለማቆም እስካልተቻለ ድረስ በውስጥ ውስጥ ይጨምራል። ጊዜው ያለፈበት_የተጠናቀቀ ተግባር የ tupleን ዕድሜ ይፈትሻል፣ expirationd_delete tupleን ይሰርዛል፣ ጊዜው ያለፈበት_ሊሰበር የሚችል ወደ ፊት መቀጠል እንዳለብን ያረጋግጣል።

ጊዜው ያለፈበት_የተግባር ኮድ፡-

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

የተግባር ኮድ ጊዜው አልፎበታል፡

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

ጊዜው ያለፈበት_ሰርዝ የተግባር ኮድ፡-

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

ጊዜው ያለፈበት_ሊሰበር የሚችል የተግባር ኮድ፡-

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

ትግበራ

የምንጭ ኮዱን በ ላይ ማየት ይችላሉ። እዚህ!

ምንጭ: hab.com

አስተያየት ያክሉ