diff --git a/README.md b/README.md index 36d79eb..2f20fb4 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ mongosh --port 27017 > db.users.find({age: {$gt: 25}}).toArray() > db.users.updateOne({name: "alice"}, {$set: {vip: true}}) > db.users.deleteOne({name: "bob"}) +> db.sessions.createIndex({expireAt: 1}, {expireAfterSeconds: 3600}) ``` ## Features @@ -41,8 +42,9 @@ mongosh --port 27017 - **Secondary indexes**: `createIndex`/`listIndexes`/`dropIndex` via the three driver commands, single-field and compound, with `unique`, `sparse` and `expireAfterSeconds` (TTL) options, persisted in the log - and rebuilt on open (compaction - re-emits them). The query planner turns equality / `$in` / range + and rebuilt on open (compaction re-emits them). A background sweeper + expires TTL-indexed documents through the ordinary logged write path. + The query planner turns equality / `$in` / range predicates into index lookups across `find`, `count`, `update`, `delete`, `findAndModify`, and a leading `$match` in `aggregate`; every candidate is re-checked against the full filter, so an index that @@ -101,9 +103,10 @@ the query planner to narrow scans. `expireAfterSeconds` must be a whole number in `[0, 2147483647]` (`0` means "expire at the stored instant"), a non-date value at the path never expires, an array of dates expires on its earliest member, and expiry is - coarse: a document stays visible until the next sweep. Changing the - expiry of an existing index is `IndexOptionsConflict` — `collMod` is not - implemented. + coarse: a document stays visible until the next sweep. Re-creating an + index with a different expiry is `IndexOptionsConflict` (85) and an + expiry on `{_id: 1}` is `InvalidIndexSpecificationOption` (197), both as + MongoDB has them. - **Multikey**: an array at an indexed path is indexed as a whole *and* element-wise, mirroring the query matcher exactly, so both `{tags: "a"}` and `{tags: ["a","b"]}` hit the index. A compound index @@ -121,7 +124,11 @@ the query planner to narrow scans. v1 limits: no index-accelerated sort, no hashed/text/geo/partial indexes, and entry insert/removal is O(n) (a sorted array) — fine for a light -database, with a B-tree or id→entry map as the follow-up. +database, with a B-tree or id→entry map as the follow-up. A TTL sweep +walks every entry of every TTL index and holds the write lock for the +whole pass, so the interval is the tuning knob: expiry is never more +precise than `--ttl-sweep-secs`, and a very large TTL index wants a +longer one. ## Not (yet) implemented @@ -129,6 +136,8 @@ database, with a B-tree or id→entry map as the follow-up. - Real cursors (all results are returned in one batch, cursor id 0) - Transactions, change streams, replicasets - Compression (OP_COMPRESSED) +- `collMod`, so an index's `expireAfterSeconds` cannot be changed in + place — drop the index and re-create it with the new expiry - `dropCollection`/`dropDatabase` write no log record, so a dropped collection (and its index definitions) resurrect on restart; and compaction never resets `log_bytes`, so every write after the first