Beberapa ketika dahulu kita berhadapan dengan masalah membersihkan tupel di ruang angkasa
Contoh yang baik untuk kami ialah modul tarantool yang dipanggil
ΠΠΏΠΈΡΠ°Π½ΠΈΠ΅
Dokumentasi untuk tarantool mempunyai yang sangat baik
Mari kita mulakan dari jauh dan lihat rupa modul yang telah tamat tempoh dihadkan dari luar:
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)
Untuk memudahkan, kami melancarkan tarantool dalam direktori tempat perpustakaan libcapped-expirationd.so kami berada. Dua fungsi dieksport dari perpustakaan: mulakan dan bunuh. Langkah pertama ialah menjadikan fungsi ini tersedia daripada Lua menggunakan box.schema.func.create dan box.schema.user.grant. Kemudian buat ruang yang tupel akan mengandungi hanya tiga medan: yang pertama ialah pengecam unik, yang kedua ialah e-mel dan yang ketiga ialah jangka hayat tupel. Kami membina indeks pokok di atas medan pertama dan memanggilnya utama. Seterusnya kami mendapat objek sambungan ke perpustakaan asli kami.
Selepas kerja persediaan, jalankan fungsi mula:
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})
Contoh ini akan berfungsi semasa pengimbasan sama seperti modul tamat tempoh, yang ditulis dalam Lua. Argumen pertama untuk fungsi permulaan ialah nama unik tugas. Yang kedua ialah pengecam ruang. Yang ketiga ialah indeks unik yang mana tupel akan dipadamkan. Keempat ialah indeks di mana tupel akan dilalui. Yang kelima ialah bilangan medan tupel dengan seumur hidup (penomboran bermula dari 1, bukan 0!). Yang keenam dan ketujuh ialah tetapan pengimbasan. 1024 ialah bilangan maksimum tupel yang boleh dilihat dalam satu transaksi. 3600 β masa imbasan penuh dalam beberapa saat.
Ambil perhatian bahawa contoh menggunakan indeks yang sama untuk merangkak dan memadam. Jika ini adalah indeks pokok, maka traversal dijalankan dari kunci yang lebih kecil kepada yang lebih besar. Jika terdapat beberapa yang lain, sebagai contoh, indeks hash, maka traversal dijalankan, sebagai peraturan, dalam susunan rawak. Semua tupel ruang diimbas dalam satu imbasan.
Mari masukkan beberapa tupel ke dalam ruang dengan seumur hidup 60 saat:
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}
Mari semak sama ada sisipan berjaya:
tarantool> box.space.tester.index.primary:select()
---
- - [0, '[email protected]', 1576418976]
- [1, '[email protected]', 1576418976]
- [2, '[email protected]', 1576418976]
...
Mari ulangi pilihan selepas 60+ saat (mengira dari permulaan sisipan tuple pertama) dan lihat bahawa modul yang telah tamat tempoh dihadkan telah diproses:
tarantool> box.space.tester.index.primary:select()
---
- []
...
Mari hentikan tugas:
capped_connection:call('libcapped-expirationd.kill', {'non-indexed'})
Mari lihat contoh kedua di mana indeks berasingan digunakan untuk merangkak:
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)
Segala-galanya di sini adalah sama seperti dalam contoh pertama, dengan beberapa pengecualian. Kami membina indeks pokok di atas medan ketiga dan memanggilnya exp. Indeks ini tidak semestinya unik, tidak seperti indeks yang dipanggil primer. Traversal akan dijalankan oleh indeks exp, dan pemadaman oleh utama. Kami ingat bahawa sebelum ini kedua-duanya dilakukan hanya menggunakan indeks utama.
Selepas kerja persediaan, kami menjalankan fungsi mula dengan hujah baharu:
capped_connection:call('libcapped-expirationd.start', {'indexed', box.space.tester.id, box.space.tester.index.primary, box.space.tester.index.exp, 3, 1024, 3600})
Mari masukkan beberapa tupel ke dalam ruang sekali lagi dengan seumur hidup 60 saat:
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}
Selepas 30 saat, dengan analogi, kami akan menambah beberapa tupel lagi:
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}
Mari semak sama ada sisipan berjaya:
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]
...
Mari ulangi pilihan selepas 60+ saat (mengira dari permulaan sisipan tuple pertama) dan lihat bahawa modul yang telah tamat tempoh dihadkan telah diproses:
tarantool> box.space.tester.index.primary:select()
---
- - [3, '[email protected]', 1576421287]
- [4, '[email protected]', 1576421287]
- [5, '[email protected]', 1576421287]
...
Masih terdapat beberapa tupel yang tinggal di angkasa yang akan mempunyai kira-kira 30 saat lagi untuk hidup. Selain itu, imbasan berhenti apabila berpindah dari tupel dengan ID 2 dan seumur hidup 1576421257 ke tupel dengan ID 3 dan seumur hidup 1576421287. Tuple dengan seumur hidup 1576421287 atau lebih tidak diimbas disebabkan oleh pesanan kunci indeks exp. Ini adalah penjimatan yang kami mahu capai pada awal-awal lagi.
Mari hentikan tugas:
capped_connection:call('libcapped-expirationd.kill', {'indexed'})
Π Π΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ
Cara terbaik untuk memberitahu tentang semua ciri projek ialah sumber asalnya.
Argumen yang kami hantar ke kaedah mula disimpan dalam struktur yang dipanggil 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;
};
Atribut nama ialah nama tugas. Atribut space_id ialah pengecam ruang. Atribut rm_index_id ialah pengecam indeks unik yang mana tupel akan dipadamkan. Atribut it_index_id ialah pengecam indeks yang mana tupel akan dilalui. Atribut it_index_type ialah jenis indeks yang mana tupel akan dilalui. Atribut filed_no ialah bilangan medan tupel dengan seumur hidup. Atribut scan_size ialah bilangan maksimum tupel yang diimbas dalam satu transaksi. Atribut scan_time ialah masa imbasan penuh dalam beberapa saat.
Kami tidak akan mempertimbangkan menghuraikan hujah. Ini adalah kerja yang susah payah tetapi mudah, yang mana perpustakaan akan membantu anda
Kami menyenaraikan prototaip semua fungsi yang digunakan untuk menghurai:
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);
Sekarang mari kita beralih kepada perkara yang paling penting - logik memintas ruang dan memadam tupel. Setiap blok tupel tidak lebih besar daripada scan_size diimbas dan diubah suai di bawah satu transaksi. Jika berjaya, urus niaga ini dilakukan; jika ralat berlaku, ia akan ditarik balik. Argumen terakhir untuk fungsi expirationd_iterate ialah penunjuk kepada iterator dari mana pengimbasan bermula atau diteruskan. Iterator ini ditambah secara dalaman sehingga ralat berlaku, ruang kehabisan, atau tidak mungkin untuk menghentikan proses terlebih dahulu. Fungsi expirationd_expired menyemak hayat tuple, expirationd_delete memadam tuple, expirationd_breakable menyemak sama ada kita perlu meneruskan.
Kod fungsi 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;
}
Kod fungsi 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;
}
Kod fungsi 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);
}
Kod fungsi 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;
}
Permohonan
Anda boleh melihat kod sumber di
Sumber: www.habr.com