index/db: heap-allocate secondary indexes
Collection.indexes held Index by value, so orderedRemove memmoved the whole ~5 KB struct and every *Index already handed out referred to a different index afterwards -- a query plan's `index` field, or a slice into an index's promoted-key buffer. The collection's own bookkeeping stayed consistent, which is why nothing noticed: only a caller holding a pointer across a drop could see it, and no test did. The new test does, and it is mutation-checked against the by-value code that this commit replaces: holding pointers to b_1 and c_1, then dropping a_1, the b_1 pointer reads "c_1". Now orderedRemove moves 8-byte pointers, the surviving indexes do not move, and only the removed one is freed. M0 needs this independently: an Index will own a file mapping once the node arena moves into the data file, and copying one by value would duplicate that ownership. Not done, though the milestone plan listed it: moving Index's inline scratch and promo buffers out of the struct. Their stated purpose was to keep those 5 KB out of a file-resident Index and to stop the memmove -- but only the node arena and overflow slab become file-resident, not the Index metadata, and boxing already fixed the memmove. Moving them would be churn with nothing left to buy.
This commit is contained in:
@@ -481,7 +481,7 @@ fn cmd_list_indexes(ctx: *Context, msg: *wire.Message, reply: *wire.Reply) !void
|
||||
id_pairs[0] = .{ .key = "v", .value = .{ .int32 = 2 } };
|
||||
id_pairs[1] = .{ .key = "key", .value = .{ .doc = &.{.{ .key = "_id", .value = .{ .int32 = 1 } }} } };
|
||||
values[0] = .{ .doc = try index_pairs_append(reply, id_pairs, "_id_") };
|
||||
for (coll.indexes.items, 0..) |*ix, i| {
|
||||
for (coll.indexes.items, 0..) |ix, i| {
|
||||
// The pairs live in the reply arena (freed with it); the values
|
||||
// array below references them.
|
||||
var pairs: std.ArrayListUnmanaged(bson.Pair) = .empty;
|
||||
|
||||
Reference in New Issue
Block a user