БъздавамС своя capped expirationd ΠΌΠΎΠ΄ΡƒΠ» Π·Π° tarantool

БъздавамС своя capped expirationd ΠΌΠΎΠ΄ΡƒΠ» Π·Π° tarantool

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

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

ОписаниС

Π’ докумСнтацията Π½Π° 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. Помним, Ρ‡Π΅ ΠΏΡ€Π΅Π΄ΠΈ ΠΈ Π΄Π²Π΅Ρ‚Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠ²Π°Ρ…Π° само с ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° 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:

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

Атрибут name β€” ΠΈΠΌΠ΅Ρ‚ΠΎ Π½Π° Π·Π°Π΄Π°Ρ‡Π°Ρ‚Π°. Атрибут space_id β€” ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π½Π° пространството. Атрибут rm_index_id β€” ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π½Π° уникалния индСкс, ΠΏΠΎ ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠ²Π° ΠΈΠ·Ρ‚Ρ€ΠΈΠ²Π°Π½Π΅Ρ‚ΠΎ Π½Π° ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠΈ. Атрибут it_index_id β€” ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π½Π° индСкса, ΠΏΠΎ ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠ²Π° ΠΎΠ±Ρ…ΠΎΠ΄ΡŠΡ‚ Π½Π° ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠΈ. Атрибут it_index_type β€” Ρ‚ΠΈΠΏ Π½Π° индСкса, ΠΏΠΎ ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠ²Π° ΠΎΠ±Ρ…ΠΎΠ΄ΡŠΡ‚ Π½Π° ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠΈ. Атрибут filed_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