ПишСм своя capped expirationd ΠΌΠΎΠ΄ΡƒΠ» Π·Π° tarantool

ПишСм своя capped expirationd ΠΌΠΎΠ΄ΡƒΠ» Π·Π° tarantool

ΠŸΡ€Π΅Π΄ΠΈ извСстно Π²Ρ€Π΅ΠΌΠ΅ сС ΡΠ±Π»ΡŠΡΠΊΠ°Ρ…ΠΌΠ΅ с ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° Π·Π° почистванСто Π½Π° ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠΈ Π² спСйсовСтС. tarantool. ΠŸΡ€ΠΎΡ†Π΅ΡΡŠΡ‚ Π½Π° почистванС Ρ‚Ρ€ΡΠ±Π²Π°ΡˆΠ΅ Π΄Π° сС стартира Π½Π΅ само ΠΊΠΎΠ³Π°Ρ‚ΠΎ ΠΏΠ°ΠΌΠ΅Ρ‚Ρ‚Π° Π½Π° tarantool Π²Π΅Ρ‡Π΅ ΡΠ²ΡŠΡ€ΡˆΠ²Π°, Π° ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»Π½ΠΎ ΠΈ с ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π° пСриодичност. Π—Π° Ρ‚Π°Π·ΠΈ Π·Π°Π΄Π°Ρ‡Π° Π² tarantool ΠΈΠΌΠ° ΠΌΠΎΠ΄ΡƒΠ», написан Π½Π° Lua, Π½Π°Ρ€Π΅Ρ‡Π΅Π½ expirationd. Π‘Π»Π΅Π΄ ΠΊΡ€Π°Ρ‚ΠΊΠΎΡ‚ΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° Ρ‚ΠΎΠ·ΠΈ ΠΌΠΎΠ΄ΡƒΠ» ΠΎΡΡŠΠ·Π½Π°Ρ…ΠΌΠ΅, Ρ‡Π΅ Π½Π΅ Π΅ подходящ Π·Π° нас: ΠΏΡ€ΠΈ постоянно почистванС Π½Π° Π³ΠΎΠ»Π΅ΠΌΠΈ ΠΎΠ±Π΅ΠΌΠΈ Π΄Π°Π½Π½ΠΈ, Lua сС забавяшС ΠΏΠΎΡ€Π°Π΄ΠΈ GC. Π—Π°Ρ‚ΠΎΠ²Π° Ρ€Π΅ΡˆΠΈΡ…ΠΌΠ΅ Π΄Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΈΠΌ собствСн ΠΌΠΎΠ΄ΡƒΠ» capped expirationd, ΠΊΠ°Ρ‚ΠΎ сС надявахмС, Ρ‡Π΅ ΠΊΠΎΠ΄ΡŠΡ‚, написан Π½Π° Π½Π°Ρ‚ΠΈΠ²Π΅Π½ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΠ½Π³ Π΅Π·ΠΈΠΊ, Ρ‰Π΅ Ρ€Π΅ΡˆΠΈ Π·Π°Π΄Π°Ρ‡ΠΈΡ‚Π΅ Π½ΠΈ ΠΏΠΎ Π½Π°ΠΉ-добрия Π½Π°Ρ‡ΠΈΠ½.

Π”ΠΎΠ±ΡŠΡ€ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π·Π° нас Π΅ ΠΌΠΎΠ΄ΡƒΠ»ΡŠΡ‚ tarantool, Π½Π°Ρ€Π΅Ρ‡Π΅Π½ memcached. Π˜Π·ΠΏΠΎΠ»Π·Π²Π°Π½ΠΈΡΡ‚ Π² Π½Π΅Π³ΠΎ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ сС основава Π½Π° Ρ‚ΠΎΠ²Π°, Ρ‡Π΅ Π² спСйса сС създава ΠΎΡ‚Π΄Π΅Π»Π½ΠΎ ΠΏΠΎΠ»Π΅, Π² ΠΊΠΎΠ΅Ρ‚ΠΎ сС посочва Π²Ρ€Π΅ΠΌΠ΅Ρ‚ΠΎ Π½Π° ΠΆΠΈΠ²ΠΎΡ‚ Π½Π° ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠ°, тоСст ttl. ΠœΠΎΠ΄ΡƒΠ»ΡŠΡ‚ Π½Π° Π·Π°Π΄Π΅Π½ ΠΏΠ»Π°Π½ сканира спСйса, сравнява ttl с Ρ‚Π΅ΠΊΡƒΡ‰ΠΎΡ‚ΠΎ Π²Ρ€Π΅ΠΌΠ΅ ΠΈ Π²Π·Π΅ΠΌΠ° Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ Π΄Π°Π»ΠΈ Π΄Π° ΠΈΠ·Ρ‚Ρ€ΠΈΠ΅ ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠ° ΠΈΠ»ΠΈ Π½Π΅. ΠšΠΎΠ΄ΡŠΡ‚ Π½Π° ΠΌΠΎΠ΄ΡƒΠ»Π° memcached Π΅ прост ΠΈ Π΅Π»Π΅Π³Π°Π½Ρ‚Π΅Π½, Π½ΠΎ Ρ‚Π²ΡŠΡ€Π΄Π΅ ΠΎΠ±Ρ‰. ΠŸΡŠΡ€Π²ΠΎ, Ρ‚ΠΎΠΉ Π½Π΅ Π²Π·Π΅ΠΌΠ° ΠΏΡ€Π΅Π΄Π²ΠΈΠ΄ Ρ‚ΠΈΠΏΠ° индСкс, ΠΏΠΎ ΠΊΠΎΠΉΡ‚ΠΎ сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠ²Π° ΠΎΠ±Ρ…ΠΎΠ΄ΡŠΡ‚ ΠΈ ΠΈΠ·Ρ‚Ρ€ΠΈΡ‚Π΅Ρ‚ΠΎ. Π’Ρ‚ΠΎΡ€ΠΎ, ΠΏΡ€ΠΈ всСки ΠΎΠ±Ρ…ΠΎΠ΄ сС сканират всички ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠΈ, Ρ‡ΠΈΠΉΡ‚ΠΎ Π±Ρ€ΠΎΠΉ ΠΌΠΎΠΆΠ΅ Π΄Π° бъдС доста голям. И Π°ΠΊΠΎ Π² ΠΌΠΎΠ΄ΡƒΠ»Π° expirationd ΠΏΡŠΡ€Π²ΠΈΡΡ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ Π΅ Ρ€Π΅ΡˆΠ΅Π½ (tree-ΠΈΠ½Π΄Π΅ΠΊΡΡŠΡ‚ Π΅ ΠΎΡ‚Π΄Π΅Π»Π΅Π½ Π² свой клас), вторият всС ΠΎΡ‰Π΅ Π½Π΅ Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ» Π½ΠΈΠΊΠ°ΠΊΠ²ΠΎ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅. Π’Π΅Π·ΠΈ Ρ‚Ρ€ΠΈ Ρ‚ΠΎΡ‡ΠΊΠΈ ΠΏΡ€Π΅Π΄ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ…Π° ΠΈΠ·Π±ΠΎΡ€Π° Π² ΠΏΠΎΠ»Π·Π° Π½Π° написванСто Π½Π° собствСн ΠΊΠΎΠ΄.

ОписаниС

Π’ докумСнтацията Π½Π° tarantool ΠΈΠΌΠ° ΠΌΠ½ΠΎΠ³ΠΎ Π΄ΠΎΠ±ΡŠΡ€ ΡƒΡ€ΠΎΠΊ относно Ρ‚ΠΎΠ²Π° ΠΊΠ°ΠΊ Π΄Π° ΠΏΠΈΡˆΠ΅Ρ‚Π΅ свои Ρ…Ρ€Π°Π½ΠΈΠΌΠΈ ΠΏΡ€ΠΎΡ†Π΅Π΄ΡƒΡ€ΠΈ Π½Π° C. Π’Π΅Π΄Π½Π°Π³Π° ΠΏΡ€Π΅Π΄Π»Π°Π³Π°ΠΌ Π΄Π° сС Π·Π°ΠΏΠΎΠ·Π½Π°Π΅Ρ‚Π΅ с Π½Π΅Π³ΠΎ, Π·Π° Π΄Π° Ρ€Π°Π·Π±Π΅Ρ€Π΅Ρ‚Π΅ Π½Π°ΡΡ‚ΡŠΠΏΠ»Π΅Π½ΠΈΡΡ‚Π° с ΠΊΠΎΠΌΠ°Π½Π΄ΠΈ ΠΈ ΠΊΠΎΠ΄, ΠΊΠΎΠΈΡ‚ΠΎ Ρ‰Π΅ срСщнСтС ΠΏΠΎ-Π΄ΠΎΠ»Ρƒ. Π‘ΡŠΡ‰ΠΎ Ρ‚Π°ΠΊΠ° Π΅ Π²Π°ΠΆΠ½ΠΎ Π΄Π° ΠΎΠ±ΡŠΡ€Π½Π΅Ρ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ Π½Π° рСфСрСнса ΠΊ ΠΎΠ±Π΅ΠΊΡ‚ΠΈΡ‚Π΅, Π½Π°Π»ΠΈΡ‡Π½ΠΈ ΠΏΡ€ΠΈ написванСто Π½Π° собствСн capped ΠΌΠΎΠ΄ΡƒΠ», Π° ΠΈΠΌΠ΅Π½Π½ΠΎ Π½Π° box, fiber, index ΠΈ txn.

НСка Π·Π°ΠΏΠΎΡ‡Π½Π΅ΠΌ ΠΎΡ‚Π΄Π°Π»Π΅Ρ‡ ΠΈ Π²ΠΈΠ΄ΠΈΠΌ ΠΊΠ°ΠΊ ΠΈΠ·Π³Π»Π΅ΠΆΠ΄Π° ΠΌΠΎΠ΄ΡƒΠ»ΡŠΡ‚ capped expirationd ΠΎΡ‚Π²ΡŠΠ½:

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. ΠžΡ‚ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°Ρ‚Π° сС Скспортират Π΄Π²Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ: start ΠΈ kill. Π’ самото Π½Π°Ρ‡Π°Π»ΠΎ трябва Π΄Π° Π½Π°ΠΏΡ€Π°Π²ΠΈΠΌ Ρ‚Π΅Π·ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π΄ΠΎΡΡ‚ΡŠΠΏΠ½ΠΈ ΠΎΡ‚ Lua с ΠΏΠΎΠΌΠΎΡ‰Ρ‚Π° Π½Π° box.schema.func.create ΠΈ box.schema.user.grant. Π‘Π»Π΅Π΄ Ρ‚ΠΎΠ²Π° създавамС спСйс, ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠΈΡ‚Π΅ Π½Π° ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ ΡΡŠΠ΄ΡŠΡ€ΠΆΠ°Ρ‚ само Ρ‚Ρ€ΠΈ ΠΏΠΎΠ»Π΅Ρ‚Π°: ΠΏΡŠΡ€Π²ΠΎΡ‚ΠΎ - ΡƒΠ½ΠΈΠΊΠ°Π»Π΅Π½ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€, Π²Ρ‚ΠΎΡ€ΠΎΡ‚ΠΎ - Π΅Π»Π΅ΠΊΡ‚Ρ€ΠΎΠ½Π½Π° ΠΏΠΎΡ‰Π°, Ρ‚Ρ€Π΅Ρ‚ΠΎΡ‚ΠΎ - Π²Ρ€Π΅ΠΌΠ΅ Π½Π° ΠΆΠΈΠ²ΠΎΡ‚ Π½Π° ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠ°. Π’ΡŠΡ€Ρ…Ρƒ ΠΏΡŠΡ€Π²ΠΎΡ‚ΠΎ ΠΏΠΎΠ»Π΅ ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°ΠΌΠ΅ tree-индСкс ΠΈ Π³ΠΎ Π½Π°Ρ€ΠΈΡ‡Π°ΠΌΠ΅ primary. Π‘Π»Π΅Π΄ Ρ‚ΠΎΠ²Π° ΠΏΠΎΠ»ΡƒΡ‡Π°Π²Π°ΠΌΠ΅ ΠΎΠ±Π΅ΠΊΡ‚ Π·Π° ΡΠ²ΡŠΡ€Π·Π²Π°Π½Π΅ с Π½Π°ΡˆΠ°Ρ‚Π° мСстна Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°.

Π‘Π»Π΅Π΄ ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ°Ρ‚Π° стартирамС функцията start:

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

Π’ΠΎΠ·ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Ρ‰Π΅ Ρ€Π°Π±ΠΎΡ‚ΠΈ ΠΏΠΎ Π°Π±ΡΠΎΠ»ΡŽΡ‚Π½ΠΎ ΡΡŠΡ‰ΠΈΡ Π½Π°Ρ‡ΠΈΠ½, ΠΊΠ°ΠΊΡ‚ΠΎ ΠΌΠΎΠ΄ΡƒΠ»ΡŠΡ‚ expirationd, написан Π½Π° Lua. ΠŸΡŠΡ€Π²ΠΈΡΡ‚ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ Π½Π° функцията start Π΅ ΡƒΠ½ΠΈΠΊΠ°Π»Π½ΠΎΡ‚ΠΎ ΠΈΠΌΠ΅ Π½Π° Π·Π°Π΄Π°Ρ‡Π°Ρ‚Π°. Вторият - ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π½Π° спСйса. ВрСтият - ΡƒΠ½ΠΈΠΊΠ°Π»Π΅Π½ индСкс, ΠΏΠΎ ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ става ΠΏΡ€Π΅ΠΌΠ°Ρ…Π²Π°Π½Π΅Ρ‚ΠΎ Π½Π° ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠΈΡ‚Π΅. Π§Π΅Ρ‚Π²ΡŠΡ€Ρ‚ΠΈΡΡ‚ - индСкс, ΠΏΠΎ ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ става ΠΎΠ±Ρ…ΠΎΠ΄ΡŠΡ‚ Π½Π° ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠΈΡ‚Π΅. ΠŸΠ΅Ρ‚ΠΈΡΡ‚ - Π½ΠΎΠΌΠ΅Ρ€ Π½Π° ΠΏΠΎΠ»Π΅Ρ‚ΠΎ Π½Π° ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠ° с Π²Ρ€Π΅ΠΌΠ΅Ρ‚ΠΎ Π½Π° ΠΆΠΈΠ²ΠΎΡ‚ (нумСрацията Π·Π°ΠΏΠΎΡ‡Π²Π° ΠΎΡ‚ 1, Π° Π½Π΅ ΠΎΡ‚ 0!). ШСстият ΠΈ сСдмият - настройки Π·Π° сканиранС. 1024 - Ρ‚ΠΎΠ²Π° Π΅ максималният Π±Ρ€ΠΎΠΉ ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠΈ, ΠΊΠΎΠΈΡ‚ΠΎ сС ΠΏΡ€Π΅Π³Π»Π΅ΠΆΠ΄Π°Ρ‚ Π² Ρ€Π°ΠΌΠΊΠΈΡ‚Π΅ Π½Π° Π΅Π΄Π½Π° транзакция. 3600 - Π²Ρ€Π΅ΠΌΠ΅Ρ‚ΠΎ Π·Π° пълно сканиранС Π² сСкунди.

ΠžΠ±ΡŠΡ€Π½Π΅Ρ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Π΅ Π·Π° ΠΎΠ±Ρ…ΠΎΠ΄ ΠΈ ΠΏΡ€Π΅ΠΌΠ°Ρ…Π²Π°Π½Π΅ Π² ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° сС ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° Π΅Π΄ΠΈΠ½ ΠΈ ΡΡŠΡ‰ индСкс. Ако Ρ‚ΠΎΠ²Π° Π΅ tree-индСкс, ΠΎΠ±Ρ…ΠΎΠ΄ΡŠΡ‚ сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠ²Π° ΠΎΡ‚ ΠΏΠΎ-малкия ΠΊΠ»ΡŽΡ‡ Π΄ΠΎ ΠΏΠΎ-голямия. Ако Π΅ някакъв Π΄Ρ€ΡƒΠ³, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ hash-индСкс, ΠΎΠ±Ρ…ΠΎΠ΄ΡŠΡ‚ ΠΎΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΎ сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠ²Π° Π² ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»Π΅Π½ Ρ€Π΅Π΄. ΠŸΡ€ΠΈ Π΅Π΄Π½ΠΎ сканиранС сС ΠΏΡ€Π΅Π³Π»Π΅ΠΆΠ΄Π°Ρ‚ всички ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠΈ Π½Π° спСйса.

НСка Π½Π°ΠΏΡ€Π°Π²ΠΈΠΌ вмъкванС Π² спСйса Π½Π° няколко ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠ° с Π²Ρ€Π΅ΠΌΠ΅ Π½Π° ΠΆΠΈΠ²ΠΎΡ‚ 60 сСкунди:

box.space.tester:insert{0, 'user0@tarantool.io', math.floor(fiber.time()) + 60}
box.space.tester:insert{1, 'user1@tarantool.io', math.floor(fiber.time()) + 60}
box.space.tester:insert{2, 'user2@tarantool.io', math.floor(fiber.time()) + 60}

Π”Π° ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ, Ρ‡Π΅ Π²ΠΌΡŠΠΊΠ²Π°Π½Π΅Ρ‚ΠΎ Π΅ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ:

tarantool> box.space.tester.index.primary:select()
---
- - [0, 'user0@tarantool.io', 1576418976]
  - [1, 'user1@tarantool.io', 1576418976]
  - [2, 'user2@tarantool.io', 1576418976]
...

Π”Π° ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΠΈΠΌ select слСд 60+ сСкунди (изчислявамС ΠΎΡ‚ Π½Π°Ρ‡Π°Π»ΠΎΡ‚ΠΎ Π½Π° Π²ΠΌΡŠΠΊΠ²Π°Π½Π΅Ρ‚ΠΎ Π½Π° ΠΏΡŠΡ€Π²ΠΈΡ ΠΊΠΎΡ€Ρ‚Π΅ΠΆ) ΠΈ Ρ‰Π΅ Π²ΠΈΠ΄ΠΈΠΌ, Ρ‡Π΅ ΠΌΠΎΠ΄ΡƒΠ»ΡŠΡ‚ capped expirationd Π²Π΅Ρ‡Π΅ Π΅ сработил:

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)

Π’ΡƒΠΊ всичко Π΅ ΡΡŠΡ‰ΠΎΡ‚ΠΎ, ΠΊΠ°ΠΊΡ‚ΠΎ Π² ΠΏΡŠΡ€Π²ΠΈΡ ΠΏΡ€ΠΈΠΌΠ΅Ρ€, с ΠΌΠ°Π»ΠΊΠΈ ΠΈΠ·ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ. Π’ΡŠΡ€Ρ…Ρƒ Ρ‚Ρ€Π΅Ρ‚ΠΎΡ‚ΠΎ ΠΏΠΎΠ»Π΅ ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°ΠΌΠ΅ tree индСкс ΠΈ Π³ΠΎ Π½Π°Ρ€ΠΈΡ‡Π°ΠΌΠ΅ exp. Π’ΠΎΠ·ΠΈ индСкс Π½Π΅ Π΅ задълТСн Π΄Π° бъдС ΡƒΠ½ΠΈΠΊΠ°Π»Π΅Π½, Π·Π° Ρ€Π°Π·Π»ΠΈΠΊΠ° ΠΎΡ‚ индСкса с ΠΈΠΌΠ΅Ρ‚ΠΎ primary. ΠžΠ±Ρ…ΠΎΠ΄ΡŠΡ‚ Ρ‰Π΅ сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠ²Π° ΠΏΠΎ индСкса exp, Π° ΠΈΠ·Ρ‚Ρ€ΠΈΠ²Π°Π½Π΅Ρ‚ΠΎ ΠΏΠΎ primary. Помним, Ρ‡Π΅ ΠΏΡ€Π΅Π΄ΠΈ ΠΈ Π΄Π²Π΅Ρ‚Π΅ дСйствия сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠ²Π°Ρ…Π° само с ΠΏΠΎΠΌΠΎΡ‰Ρ‚Π° Π½Π° основния индСкс.

Π‘Π»Π΅Π΄ ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ°Ρ‚Π° стартирамС функцията start с Π½ΠΎΠ²ΠΈ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΈ:

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, 'user0@tarantool.io', math.floor(fiber.time()) + 60}
box.space.tester:insert{1, 'user1@tarantool.io', math.floor(fiber.time()) + 60}
box.space.tester:insert{2, 'user2@tarantool.io', math.floor(fiber.time()) + 60}

Π‘Π»Π΅Π΄ 30 сСкунди, ΠΏΠΎ аналогия, добавямС ΠΎΡ‰Π΅ няколко ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠ°:

box.space.tester:insert{3, 'user3@tarantool.io', math.floor(fiber.time()) + 60}
box.space.tester:insert{4, 'user4@tarantool.io', math.floor(fiber.time()) + 60}
box.space.tester:insert{5, 'user5@tarantool.io', math.floor(fiber.time()) + 60}

Π”Π° ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ, Ρ‡Π΅ Π²ΠΌΡŠΠΊΠ²Π°Π½Π΅Ρ‚ΠΎ Π΅ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ:

tarantool> box.space.tester.index.primary:select()
---
- - [0, 'user0@tarantool.io', 1576421257]
  - [1, 'user1@tarantool.io', 1576421257]
  - [2, 'user2@tarantool.io', 1576421257]
  - [3, 'user3@tarantool.io', 1576421287]
  - [4, 'user4@tarantool.io', 1576421287]
  - [5, 'user5@tarantool.io', 1576421287]
...

Π”Π° ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΠΈΠΌ select слСд 60+ сСкунди (изчислявамС ΠΎΡ‚ Π½Π°Ρ‡Π°Π»ΠΎΡ‚ΠΎ Π½Π° Π²ΠΌΡŠΠΊΠ²Π°Π½Π΅Ρ‚ΠΎ Π½Π° ΠΏΡŠΡ€Π²ΠΈΡ ΠΊΠΎΡ€Ρ‚Π΅ΠΆ) ΠΈ Ρ‰Π΅ Π²ΠΈΠ΄ΠΈΠΌ, Ρ‡Π΅ ΠΌΠΎΠ΄ΡƒΠ»ΡŠΡ‚ capped expirationd Π²Π΅Ρ‡Π΅ Π΅ сработил:

tarantool> box.space.tester.index.primary:select()
---
- - [3, 'user3@tarantool.io', 1576421287]
  - [4, 'user4@tarantool.io', 1576421287]
  - [5, 'user5@tarantool.io', 1576421287]
...

Π’ спСйса останаха ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠΈ, ΠΊΠΎΠΈΡ‚ΠΎ Ρ‰Π΅ са Π² сила ΠΎΡ‰Π΅ ΠΎΠΊΠΎΠ»ΠΎ 30 сСкунди. ОсвСн Ρ‚ΠΎΠ²Π°, сканиранСто спря ΠΏΡ€ΠΈ ΠΏΡ€Π΅ΠΌΠΈΠ½Π°Π²Π°Π½Π΅ ΠΎΡ‚ ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠ° с ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ 2 ΠΈ Π²Ρ€Π΅ΠΌΠ΅Ρ‚Ρ€Π°Π΅Π½Π΅ 1576421257 към ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠ° с ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ 3 ΠΈ Π²Ρ€Π΅ΠΌΠ΅Ρ‚Ρ€Π°Π΅Π½Π΅ 1576421287. ΠšΠΎΡ€Ρ‚Π΅ΠΆΠΈΡ‚Π΅ с Π²Ρ€Π΅ΠΌΠ΅Ρ‚Ρ€Π°Π΅Π½Π΅ 1576421287 ΠΈ ΠΏΠΎΠ²Π΅Ρ‡Π΅ Π½Π΅ бяха ΠΏΡ€Π΅Π³Π»Π΅Π΄Π°Π½ΠΈ Π±Π»Π°Π³ΠΎΠ΄Π°Ρ€Π΅Π½ΠΈΠ΅ Π½Π° ΠΏΠΎΠ΄Ρ€Π΅Π΄Π±Π°Ρ‚Π° Π½Π° ΠΊΠ»ΡŽΡ‡ΠΎΠ²Π΅Ρ‚Π΅ Π½Π° индСкса exp. Π’ΠΎΠ²Π° Π΅ икономията, която искахмС Π΄Π° постигнСм Π² Π½Π°Ρ‡Π°Π»ΠΎΡ‚ΠΎ.

Π”Π° спрСм Π·Π°Π΄Π°Ρ‡Π°Ρ‚Π°:

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

РСализация

Най-Π΄ΠΎΠ±Ρ€Π΅ Π·Π° всички особСности Π½Π° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π²ΠΈΠ½Π°Π³ΠΈ Ρ‰Π΅ Ρ€Π°Π·ΠΊΠ°ΠΆΠ΅ нСговият ΠΈΠ·Ρ‚ΠΎΡ‡Π½ΠΈΠΊ. ΠΊΠΎΠ΄! Π’ Ρ€Π°ΠΌΠΊΠΈΡ‚Π΅ Π½Π° публикацията ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° сС спрСм само Π½Π° Π½Π°ΠΉ-Π²Π°ΠΆΠ½ΠΈΡ‚Π΅ ΠΌΠΎΠΌΠ΅Π½Ρ‚ΠΈ, Π° ΠΈΠΌΠ΅Π½Π½ΠΎ, Π½Π° Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠΈΡ‚Π΅ Π·Π° ΠΎΠ±Ρ…ΠΎΠ΄ Π½Π° спСйса.

АргумСнтитС, ΠΊΠΎΠΈΡ‚ΠΎ ΠΏΡ€Π΅Π΄Π°Π²Π°ΠΌΠ΅ Π½Π° ΠΌΠ΅Ρ‚ΠΎΠ΄Π° start, сС ΡΡŠΡ…Ρ€Π°Π½ΡΠ²Π°Ρ‚ Π² структура, Π½Π°Ρ€Π΅Ρ‡Π΅Π½Π° expirationd_task:

структура 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;
};

Атрибут name β€” Ρ‚ΠΎΠ²Π° Π΅ ΠΈΠΌΠ΅Ρ‚ΠΎ Π½Π° Π·Π°Π΄Π°Ρ‡Π°Ρ‚Π°. Атрибут space_id β€” ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π½Π° пространството. Атрибут rm_index_id β€” ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π½Π° уникалния индСкс, ΠΏΠΎ ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠ²Π° ΠΈΠ·Ρ‚Ρ€ΠΈΠ²Π°Π½Π΅Ρ‚ΠΎ Π½Π° записи. Атрибут it_index_id β€” ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π½Π° индСкса, ΠΏΠΎ ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠ²Π° ΠΎΠ±Ρ…ΠΎΠ΄Π° Π½Π° записитС. Атрибут it_index_type β€” Ρ‚ΠΈΠΏ Π½Π° индСкса, ΠΏΠΎ ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠ²Π° ΠΎΠ±Ρ…ΠΎΠ΄Π° Π½Π° записитС. Атрибут field_no β€” Π½ΠΎΠΌΠ΅Ρ€ Π½Π° ΠΏΠΎΠ»Π΅Ρ‚ΠΎ Π½Π° записа с Π²Ρ€Π΅ΠΌΠ΅Ρ‚ΠΎ Π½Π° ΠΆΠΈΠ²ΠΎΡ‚. Атрибут scan_size β€” максималното количСство записи, ΠΊΠΎΠ΅Ρ‚ΠΎ Ρ‰Π΅ сС ΠΏΡ€Π΅Π³Π»Π΅Π΄Π° Π² Ρ€Π°ΠΌΠΊΠΈΡ‚Π΅ Π½Π° Π΅Π΄Π½Π° транзакция. Атрибут scan_time β€” Π²Ρ€Π΅ΠΌΠ΅Ρ‚ΠΎ Π·Π° пълно сканиранС Π² сСкунди.

Няма Π΄Π° Ρ€Π°Π·Π³Π»Π΅ΠΆΠ΄Π°ΠΌΠ΅ парсиранСто Π½Π° Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΈΡ‚Π΅. Π’ΠΎΠ²Π° Π΅ Ρ‚Ρ€ΡƒΠ΄ΠΎΠ΅ΠΌΠΊΠ°, Π½ΠΎ Π½Π΅ слоТна Ρ€Π°Π±ΠΎΡ‚Π°, Π² която Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°Ρ‚Π° 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);

А сСга Π΄Π° ΠΏΡ€Π΅ΠΌΠΈΠ½Π΅ΠΌ към Π½Π°ΠΉ-Π²Π°ΠΆΠ½ΠΎΡ‚ΠΎ β€” Π»ΠΎΠ³ΠΈΠΊΠ°Ρ‚Π° Π·Π° ΠΎΠ±Ρ…ΠΎΠ΄ Π½Π° спСйса ΠΈ ΠΈΠ·Ρ‚Ρ€ΠΈΠ²Π°Π½Π΅ Π½Π° ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠΈ. ВсСки Π±Π»ΠΎΠΊ ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠΈ с Ρ€Π°Π·ΠΌΠ΅Ρ€ Π½Π΅ ΠΏΠΎ-голям ΠΎΡ‚ scan_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 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;
}

ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅

ΠœΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° сС Π·Π°ΠΏΠΎΠ·Π½Π°Π΅Ρ‚Π΅ с изходния ΠΊΠΎΠ΄ Π½Π° Ρ‚ΡƒΠΊ!

Π˜Π·Ρ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

ΠšΡƒΠΏΠ΅Ρ‚Π΅ Π½Π°Π΄Π΅ΠΆΠ΄Π΅Π½ хостинг Π·Π° сайтовС със Π·Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ DDoS, VPS ΠΈ VDS ΡΡŠΡ€Π²ΡŠΡ€ΠΈ πŸ”₯ ΠšΡƒΠΏΠ΅Ρ‚Π΅ Π½Π°Π΄Π΅ΠΆΠ΄Π΅Π½ хостинг Π·Π° сайтовС със Π·Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ DDoS, VPS ΠΈ VDS ΡΡŠΡ€Π²ΡŠΡ€ΠΈ | ProHoster