handleExpiredKeys processes a batch of expiration events in a single transaction. This batch processing approach significantly reduces transaction overhead compared to processing each expired key individually. It validates timestamps to prevent race conditions where a key is: 1. Set with TTL (times
(events []*ttl.ExpirationEvent)
| 1100 | // |
| 1101 | // By comparing timestamps, we ensure only the originally expired key is deleted. |
| 1102 | func (db *DB) handleExpiredKeys(events []*ttl.ExpirationEvent) { |
| 1103 | if len(events) == 0 { |
| 1104 | return |
| 1105 | } |
| 1106 | |
| 1107 | _ = db.Update(func(tx *Tx) error { |
| 1108 | // Group events by bucket to avoid repeated bucket lookups |
| 1109 | bucketEvents := make(map[uint64][]*ttl.ExpirationEvent) |
| 1110 | for _, event := range events { |
| 1111 | bucketEvents[event.BucketId] = append(bucketEvents[event.BucketId], event) |
| 1112 | } |
| 1113 | |
| 1114 | for bucketId, evs := range bucketEvents { |
| 1115 | bucket, err := db.bucketMgr.GetBucketById(bucketId) |
| 1116 | if err != nil { |
| 1117 | continue |
| 1118 | } |
| 1119 | |
| 1120 | idx, ok := db.Index.BTree.exist(bucketId) |
| 1121 | if !ok { |
| 1122 | continue |
| 1123 | } |
| 1124 | |
| 1125 | for _, event := range evs { |
| 1126 | // Use FindForVerification to get the record without triggering callbacks (avoid recursion) |
| 1127 | record, found := idx.FindForVerification(event.Key) |
| 1128 | if !found { |
| 1129 | continue |
| 1130 | } |
| 1131 | |
| 1132 | // Only delete if timestamp matches (same record that expired) |
| 1133 | // Also verify it's actually expired (in case it was updated) |
| 1134 | if record.Timestamp == event.Timestamp && db.ttlService.IsExpired(record.TTL, record.Timestamp) { |
| 1135 | _ = tx.put(bucket.Name, event.Key, nil, Persistent, DataDeleteFlag, uint64(db.ttlService.NowMillis()), bucket.Ds) |
| 1136 | // Deregister from timing wheel to prevent duplicate expiration events |
| 1137 | db.ttlService.DeregisterKeyFromActiveExpiration(bucketId, event.Key) |
| 1138 | } |
| 1139 | } |
| 1140 | } |
| 1141 | |
| 1142 | return nil |
| 1143 | }) |
| 1144 | } |
| 1145 | |
| 1146 | func (db *DB) rebuildBucketManager() error { |
| 1147 | bucketFilePath := db.opt.Dir + "/" + BucketStoreFileName |
nothing calls this directly
no test coverage detected