~bigbes/tarantool-etcd · events

d7td0mgcv9aro8ppnkgknqnbn4saht8b · 87 rows

idissue_idevent_typeactorold_valuenew_valuecommentcreated_at
000fef98-f0eb-4c85-8118-79fdda5bff24tarantool-etcd-4y9createdEugene BlikhNULL2026-05-19T17:54:52Z
01265226-b3bd-4381-866a-6dc7a85b54a1tarantool-etcd-8zmcreatedEugene BlikhNULL2026-05-19T17:54:13Z
054042b2-efb1-4780-906f-ea6461c2bbe0tarantool-etcd-5zxcreatedEugene BlikhNULL2026-05-19T17:54:36Z
0664fe02-5b7b-4bfe-a708-5db2886620eftarantool-etcd-mo5createdEugene BlikhNULL2026-05-19T17:54:26Z
07d96215-4a88-46f5-b1c9-b30556edaec5tarantool-etcd-70jcreatedEugene BlikhNULL2026-05-19T17:54:28Z
0bc59661-158a-48bf-b22b-78f0adeefeb1tarantool-etcd-tt6createdEugene BlikhNULL2026-05-20T09:17:56Z
0cb660ac-8609-49d6-979e-b78259436280tarantool-etcd-3c2createdEugene BlikhNULL2026-05-19T17:54:23Z
12ea9ddb-ef88-4b53-877b-f86778387cb6tarantool-etcd-3spupdatedEugene Blikh{"id":"tarantool-etcd-3sp","title":"LeaseKeepAlive fsyncs WAL on every renew","description":"On btrfs SSD bench (2026-05-19 disk run), LeaseKeepAlive/n_X drops from 4 234 ops/s (tmpfs) to 207 ops/s on tarantool while etcd holds at ~7 400 ops/s in both configs.\n\np50 goes from 224 µs (tmpfs) to 4 548 µs (disk) — exactly one btrfs fsync. Root cause at app/etcd/lease.lua:191:\n\n box.space.leases:update(id, {{'=', 'expiry_time', now + lease.ttl}})\n\nThe leases space is is_sync=true so every keep-alive does a full WAL append + fsync. Etcd's KeepAlive is an in-memory TTL bump with no disk write.\n\nFix sketch: split expiry into an in-memory map (refreshed on every KeepAlive) and persist only on grant/revoke. The expiry fiber should read from the in-memory map. Trade-off: leases may extend further into the future than the on-disk record after a crash, which is fine — clients have to re-keep-alive after reconnect anyway.\n\nSee docs/BENCH.md Linux x86_64 disk section (Open follow-ups).","design":"GOAL: lease keep-alive must not touch the WAL. Mirror etcd's split — durable\nstate = {lease record, granted TTL, attached keys}; ephemeral leader-local\nstate = the expiry deadline (refreshed on every keep-alive, never persisted).\n\n=== STATE MODEL ===\nAdd a module-level in-memory map in app/etcd/lease.lua:\n local deadlines = {} -- [lease_id] = monotonic deadline (clock.monotonic()+ttl)\nThis is leader-local. Followers never keep-alive (the gRPC write gate routes\nLeaseKeepAlive to the leader), and only the leader runs the expiry fiber and\ncan revoke. So the countdown is structurally a leader concern.\n\nThe `leases` space (schema.lua:97-118) stays is_sync=true and keeps its\n{id, ttl, expiry_time, granted_ttl} format. The `expiry_time` FIELD and its\nTREE index (schema.lua:113) become vestigial — written once at grant, never\nthe source of liveness again. Leave them to avoid a space migration; an\noptional follow-up can drop the field+index. Nothing reads expiry_time after\nthis change.\n\n=== HANDLER CHANGES (app/etcd/lease.lua) ===\n1. grant() ~L70: after `box.space.leases:insert(...)`, seed\n `deadlines[id] = now + ttl`. Insert still persists (durable, required).\n2. keepalive() ~L191: REPLACE\n box.space.leases:update(id, {{'=', 'expiry_time', now + lease.ttl}})\n with\n deadlines[id] = clock.monotonic() + lease.ttl\n Keep the `box.space.leases:get(id)` existence check above it (cheap read,\n no fsync) — it supplies lease.ttl and preserves the NOT_FOUND-raises\n contract the gRPC stream handler depends on (see L169-171).\n3. revoke() ~L150: after `box.space.leases:delete(id)`, clear\n `deadlines[id] = nil`.\n4. time_to_live() ~L236: REPLACE `lease.expiry_time` read with `deadlines[id]`.\n If deadlines[id] is nil (lease loaded but not yet rebuilt), fall back to\n `clock.monotonic() + lease.granted_ttl`. remaining = max(0, floor(dl - now)).\n5. expiry_loop() L287-338: REPLACE the `box.space.leases.index.expiry_time`\n scan (L302-309) with a scan of `deadlines`: collect ids where\n `deadline \u003c= now`. Plain full-table scan is fine (numeric compares in Lua,\n runs every 500ms); a min-heap (etcd's leaseExpiredNotifier shape) is the\n optional optimization if lease counts get large. revoke() already nils the\n map entry on success.\n\n=== REBUILD ON PROMOTE ===\nAdd lease.M.rebuild_deadlines():\n clears `deadlines`, then for each tuple in box.space.leases:pairs() sets\n deadlines[tuple.id] = clock.monotonic() + tuple.ttl\nCall it in the RW branch of the box.watch('box.status', ...) callback in\napp/roles/etcd.lua (L341-353), immediately before lease.start_expiry().\nThis resets every inherited lease's deadline to a full-TTL grace period on the\nnew leader — exactly etcd's failover behavior.\n\n=== LATENT BUG THIS ALSO FIXES ===\nexpiry_time is currently computed as clock.monotonic()+ttl and REPLICATED.\nclock.monotonic() is process-local (relative to boot), so the persisted value\nis meaningless on any other node. Today a promoted replica's fiber scans\ninherited expiry_time values from a different monotonic timeline — could\nexpire leases instantly or never. Rebuild-on-promote with the new leader's own\nclock removes this entirely.","status":"open","priority":2,"issue_type":"bug","owner":"bigbes@gmail.com","created_at":"2026-05-19T17:33:47Z","created_by":"Eugene Blikh","updated_at":"2026-05-20T04:39:03Z"}{"acceptance_criteria":"- keepalive issues ZERO WAL writes: box.info.lsn delta == 0 across N successive\n M.keepalive() calls on the same lease.\n- BenchmarkLeaseKeepAlive/n_* on btrfs SSD (work.lab.local, real-disk run)\n recovers from 207 ops/s to within ~2x of etcd (~4000+ ops/s, near the tmpfs\n baseline). Re-run: TMPDIR=$HOME/bench-data go test -run=^$ \\\n -bench=^BenchmarkLeaseKeepAlive$ -benchtime=5s ./bench/\n- Lease still expires correctly: grant short TTL, no keep-alive, attached keys\n are deleted by the fiber after TTL elapses; keep-alive before TTL prevents it.\n- TimeToLive reflects the latest keep-alive (remaining resets to ~ttl after a\n renew).\n- Promote rebuilds deadlines: a freshly-promoted leader expires inherited\n leases using its own monotonic clock (no instant-expiry, no never-expiry).\n- All existing lease conformance cells (tarantool, tarantool_json,\n tarantool_rs3) and Lua lease tests pass.","notes":"TESTS (add Lua-side tests pinning the fix per the project's regression rule):\n- no-WAL: assert box.info.lsn unchanged across keepalive calls.\n- liveness: keepalive refreshes deadline (TimeToLive resets, lease survives).\n- promote rebuild: use the box.cfg{read_only=true}...{read_only=false}+\n box.ctl.promote() in-process follower-simulation pattern (see role_test.lua\n group role/write_gates_in_process) to verify rebuild_deadlines repopulates.\n- cross-node: optionally exercise via the replicaset harness that a promoted\n replica expires an inherited lease.\nConformance already covers cross-wire correctness; this is about the Lua unit\npins + the bench recovery number.\n\nDOCS: update docs/BENCH.md Linux x86_64 disk section once re-benched; remove\nthe LeaseKeepAlive \"bug\" annotation from the headline table.\n\nSCOPE NOTE: leave the expiry_time field + index in place (no migration). Only\nthe keepalive write path and the fiber's liveness source change."}NULL2026-05-20T07:39:22Z
1632bb64-4a7b-4e1c-b45e-a87309d9a8dbtarantool-etcd-ueecreatedEugene BlikhNULL2026-05-20T09:17:54Z
18fe139b-df94-451a-8e87-a2ca72e657e0tarantool-etcd-ymmcreatedEugene BlikhNULL2026-05-19T17:54:41Z
1ce593c2-ac19-43ae-b8a2-3334751c95ddtarantool-etcd-nwlcreatedEugene BlikhNULL2026-05-19T17:54:11Z
1d7bbef0-a625-4b7e-9459-5d59c8029828tarantool-etcd-w8qcreatedEugene BlikhNULL2026-05-19T17:53:51Z
1d8a485e-0bb1-4902-8690-ecd2e4d36a43tarantool-etcd-929createdEugene BlikhNULL2026-05-19T17:54:30Z
1fa4e29e-2f25-4419-9818-77e0f4af47b2tarantool-etcd-9z2createdEugene BlikhNULL2026-05-19T16:34:06Z
2921ede2-b70c-44f4-8e52-54255702370atarantool-etcd-dmtcreatedEugene BlikhNULL2026-05-19T17:54:53Z
2d2828f8-6cf0-4859-9db8-430ae1f7a9d7tarantool-etcd-g1acreatedEugene BlikhNULL2026-05-19T17:54:25Z
2e9cfbea-e2f5-4e74-8f33-41ce4f2a9370tarantool-etcd-iz4createdEugene BlikhNULL2026-05-19T17:54:15Z
323218d7-991c-4baa-9e61-32ec89198c10tarantool-etcd-7kbcreatedEugene BlikhNULL2026-05-19T17:54:18Z
353c3076-8b72-42ef-8fb5-ef1f700df311tarantool-etcd-ovtcreatedEugene BlikhNULL2026-05-19T17:54:21Z
35af2e9c-c033-4f03-8b56-efe92ec8b347tarantool-etcd-0uwcreatedEugene BlikhNULL2026-05-19T17:53:54Z
3690d19b-6bf7-4ee3-b57b-858ee5a8f937tarantool-etcd-3spcreatedEugene BlikhNULL2026-05-19T20:33:47Z
36a3b9e9-2035-470e-ab66-3380d4d56902tarantool-etcd-0gvcreatedEugene BlikhNULL2026-05-19T17:54:09Z
39066b96-06b0-4e17-8050-a78a8b00be14tarantool-etcd-zwscreatedEugene BlikhNULL2026-05-20T09:17:55Z
3bae43c8-27f2-4820-8048-4a02a89a9d4dtarantool-etcd-3cocreatedEugene BlikhNULL2026-05-19T17:54:16Z
3c8a8e00-bb58-4ade-b7b1-e19dd83a32e0tarantool-etcd-p3screatedEugene BlikhNULL2026-05-19T17:54:48Z
411558db-b3ff-4790-bc94-3f7d1eb411c4tarantool-etcd-j1ccreatedEugene BlikhNULL2026-05-19T16:34:30Z
42dd73d1-1e61-419b-9025-aacb3eaa915etarantool-etcd-h8rcreatedEugene BlikhNULL2026-05-19T17:54:50Z
430012bd-a6c5-41d6-96c2-81ec1646408dtarantool-etcd-8t0createdEugene BlikhNULL2026-05-19T17:54:00Z
436c1852-ceec-470b-a798-efd84bcdab75tarantool-etcd-40screatedEugene BlikhNULL2026-05-19T17:54:01Z
455cfe4d-7294-4c69-9323-3fddcdc09ee6tarantool-etcd-9cdcreatedEugene BlikhNULL2026-05-19T17:53:58Z
48efda0f-f28e-419d-85ac-3642a7629eb7tarantool-etcd-828createdEugene BlikhNULL2026-05-19T17:54:27Z
4bac8298-81b3-41fe-b1de-2c987975ddfftarantool-etcd-sdtcreatedEugene BlikhNULL2026-05-19T17:54:04Z
571acc91-b6a6-4750-aeb2-c1b07177cb5atarantool-etcd-bg4createdEugene BlikhNULL2026-05-19T17:54:14Z
57625cfc-bfcf-4d28-bee1-8d160230d03etarantool-etcd-bq8createdEugene BlikhNULL2026-05-19T17:53:59Z
57a8f358-4b13-4ab0-b57c-033b3bc71f64tarantool-etcd-7eycreatedEugene BlikhNULL2026-05-20T08:48:14Z
5867eb7d-94e2-44f6-a474-655d28d0c76ftarantool-etcd-60xcreatedEugene BlikhNULL2026-05-19T17:54:01Z
5e3d435c-1dc9-4bdd-a716-a8c79670316atarantool-etcd-zwgcreatedEugene BlikhNULL2026-05-19T17:54:07Z
60d04eed-2387-4f84-89a7-0ef5988c0385tarantool-etcd-rzscreatedEugene BlikhNULL2026-05-19T17:54:23Z
61951fb7-6389-47f7-bb7c-f727d1698ac2tarantool-etcd-hcocreatedEugene BlikhNULL2026-05-19T17:54:50Z
6241ce98-aac8-405f-ad11-ea6aebd811e3tarantool-etcd-iijcreatedEugene BlikhNULL2026-05-19T17:54:17Z
6d0d6a46-bde1-4834-8f10-92d250cd196ctarantool-etcd-rzhcreatedEugene BlikhNULL2026-05-19T17:54:32Z
7029e6cf-59f7-4c8c-bdfd-55b9721bfdfdtarantool-etcd-4nrcreatedEugene BlikhNULL2026-05-19T17:54:34Z
70edafc2-4689-4668-acad-4ca1fa4c04e5tarantool-etcd-234createdEugene BlikhNULL2026-05-19T16:34:48Z
735f864c-3b3d-4297-b6e0-794f09727eeatarantool-etcd-lkocreatedEugene BlikhNULL2026-05-19T16:33:55Z
767c403c-52ae-425f-a006-951eeaf365eftarantool-etcd-97vcreatedEugene BlikhNULL2026-05-19T17:54:39Z
792d9f81-6e4c-4c6f-ba75-cb138eb54414tarantool-etcd-sqvcreatedEugene BlikhNULL2026-05-19T17:54:45Z
7d3e60cb-8582-4958-8d4f-298009a7c532tarantool-etcd-9ljcreatedEugene BlikhNULL2026-05-19T17:54:07Z
81308796-b73c-4206-b890-159e69e50815tarantool-etcd-laccreatedEugene BlikhNULL2026-05-19T16:34:01Z
8a94766d-a19a-4201-8fc3-18b0c83ea47atarantool-etcd-9z2updatedEugene Blikh{"id":"tarantool-etcd-9z2","title":"Phase 5f — Watch option coverage","description":"Per-option density on Watch RPCs. Big stream-shaped surface, highest remaining value but also highest effort. Run after Phase 5e.\n\nLikely tests:\n- TestWatchWithFilterPut / TestWatchWithFilterDelete (server-side event filtering)\n- TestWatchProgressNotifyExplicit (RequestProgress on demand vs the implicit 10-minute heartbeat already covered)\n- TestWatchWithFragment (large-response fragmentation — may surface a tarantool-side gap)\n- TestWatchWithPrevKV (per-watcher prev-kv flag, distinct from WithPrevKV on Put/Delete)\n- TestWatchFromCompactedRevision (ErrCompacted returned on the stream, not as a typed gRPC status)","acceptance_criteria":"Each listed test ported, runs on all four cells, passes (or documented as a known gap with cross-reference).","notes":"Source: docs/TODO.md \"Open / Conformance matrix — Phase 5 option coverage\".","status":"open","priority":2,"issue_type":"task","owner":"bigbes@gmail.com","created_at":"2026-05-19T13:34:06Z","created_by":"Eugene Blikh","updated_at":"2026-05-19T13:34:06Z"}{"notes":"Source: docs/TODO.md \"Open / Conformance matrix — Phase 5 option coverage\".\n\nPriority note (TestWatchWithPrevKV): Tarantool EE uses etcd as a centralized-config backend (config.storage / etcd config source in TT 3.x). On boot it reads config from etcd and opens a Watch with prev_kv set to diff old-vs-new config on live reload. So Watch prev_kv is exercised by a first-class ecosystem consumer, not just the conformance suite — it should be treated as the highest-value test in this group for drop-in TT EE compatibility.\n\nImplementation already exists (feature built, conformance assertion missing):\n- app/etcd/watch.lua:83 lookup_prev_kv() walks kv_history backwards (LT on mod_revision) for the prior non-tombstone value\n- app/etcd/watch.lua:268 stores per-watcher flag; propagated via grpc.lua:358, json.lua:205, server.lua:185\n- auth.lua:317 requires READ perm when prev_kv requested\nRemaining work for prev_kv is the TestWatchWithPrevKV conformance case against real etcd 3.6, not the Lua implementation."}NULL2026-05-20T09:34:10Z
8ce5904b-3788-4480-95ba-f0419b7dae79tarantool-etcd-gz4createdEugene BlikhNULL2026-05-19T17:53:52Z