@@ -1263,6 +1263,13 @@ func (db *DB) Compact(ctx context.Context, dstLevel int) (*ltx.FileInfo, error)
12631263 db .maxLTXFileInfos .m [dstLevel ] = info
12641264 db .maxLTXFileInfos .Unlock ()
12651265
1266+ // If this is L1, clean up L0 files that are below the minTXID.
1267+ if dstLevel == 1 {
1268+ if err := db .EnforceRetentionByTXID (ctx , 0 , maxTXID ); err != nil {
1269+ db .Logger .Error ("enforce L0 retention" , "error" , err )
1270+ }
1271+ }
1272+
12661273 return info , nil
12671274}
12681275
@@ -1284,6 +1291,91 @@ func (db *DB) Snapshot(ctx context.Context) (*ltx.FileInfo, error) {
12841291 return info , nil
12851292}
12861293
1294+ // EnforceSnapshotRetention enforces retention of the snapshot level in the database by timestamp.
1295+ func (db * DB ) EnforceSnapshotRetention (ctx context.Context , timestamp time.Time ) (minSnapshotTXID ltx.TXID , err error ) {
1296+ db .Logger .Debug ("enforcing snapshot retention" , "timestamp" , timestamp )
1297+
1298+ itr , err := db .Replica .Client .LTXFiles (ctx , SnapshotLevel , 0 )
1299+ if err != nil {
1300+ return 0 , fmt .Errorf ("fetch ltx files: %w" , err )
1301+ }
1302+ defer itr .Close ()
1303+
1304+ var deleted []* ltx.FileInfo
1305+ var lastInfo * ltx.FileInfo
1306+ for itr .Next () {
1307+ info := itr .Item ()
1308+ lastInfo = info
1309+
1310+ // If this snapshot is before the retention timestamp, mark it for deletion.
1311+ if info .CreatedAt .Before (timestamp ) {
1312+ deleted = append (deleted , info )
1313+ continue
1314+ }
1315+
1316+ // Track the lowest snapshot TXID so we can enforce retention in lower levels.
1317+ // This is only tracked for snapshots not marked for deletion.
1318+ if minSnapshotTXID == 0 || info .MaxTXID < minSnapshotTXID {
1319+ minSnapshotTXID = info .MaxTXID
1320+ }
1321+ }
1322+
1323+ // If this is the snapshot level, we need to ensure that at least one snapshot exists.
1324+ if len (deleted ) > 0 && deleted [len (deleted )- 1 ] == lastInfo {
1325+ deleted = deleted [:len (deleted )- 1 ]
1326+ }
1327+
1328+ // Remove all files marked for deletion.
1329+ for _ , info := range deleted {
1330+ db .Logger .Info ("deleting ltx file" , "level" , SnapshotLevel , "minTXID" , info .MinTXID , "maxTXID" , info .MaxTXID )
1331+ }
1332+ if err := db .Replica .Client .DeleteLTXFiles (ctx , deleted ); err != nil {
1333+ return 0 , fmt .Errorf ("remove ltx files: %w" , err )
1334+ }
1335+
1336+ return minSnapshotTXID , nil
1337+ }
1338+
1339+ // EnforceRetentionByTXID enforces retention so that any LTX files below
1340+ // the target TXID are deleted. Always keep at least one file.
1341+ func (db * DB ) EnforceRetentionByTXID (ctx context.Context , level int , txID ltx.TXID ) (err error ) {
1342+ db .Logger .Debug ("enforcing retention" , "level" , level , "txid" , txID )
1343+
1344+ itr , err := db .Replica .Client .LTXFiles (ctx , level , 0 )
1345+ if err != nil {
1346+ return fmt .Errorf ("fetch ltx files: %w" , err )
1347+ }
1348+ defer itr .Close ()
1349+
1350+ var deleted []* ltx.FileInfo
1351+ var lastInfo * ltx.FileInfo
1352+ for itr .Next () {
1353+ info := itr .Item ()
1354+ lastInfo = info
1355+
1356+ // If this file's maxTXID is below the target TXID, mark it for deletion.
1357+ if info .MaxTXID < txID {
1358+ deleted = append (deleted , info )
1359+ continue
1360+ }
1361+ }
1362+
1363+ // Ensure we don't delete the last file.
1364+ if len (deleted ) > 0 && deleted [len (deleted )- 1 ] == lastInfo {
1365+ deleted = deleted [:len (deleted )- 1 ]
1366+ }
1367+
1368+ // Remove all files marked for deletion.
1369+ for _ , info := range deleted {
1370+ db .Logger .Info ("deleting ltx file" , "level" , level , "minTXID" , info .MinTXID , "maxTXID" , info .MaxTXID )
1371+ }
1372+ if err := db .Replica .Client .DeleteLTXFiles (ctx , deleted ); err != nil {
1373+ return fmt .Errorf ("remove ltx files: %w" , err )
1374+ }
1375+
1376+ return nil
1377+ }
1378+
12871379// monitor runs in a separate goroutine and monitors the database & WAL.
12881380func (db * DB ) monitor () {
12891381 ticker := time .NewTicker (db .MonitorInterval )
0 commit comments