fix(unified-storage): unlist the deleted resource's versions (#102588)

This commit is contained in:
Mustafa Sencer Özcan
2025-03-27 18:34:37 +01:00
committed by GitHub
parent d10fdc0f02
commit fe1a72e41b
12 changed files with 478 additions and 50 deletions
+68 -9
View File
@@ -521,22 +521,19 @@ func (b *backend) ReadResource(ctx context.Context, req *resource.ReadRequest) *
// TODO: validate key ?
if req.ResourceVersion > 0 {
return b.readHistory(ctx, req.Key, req.ResourceVersion)
}
readReq := &sqlResourceReadRequest{
SQLTemplate: sqltemplate.New(b.dialect),
Request: req,
Response: NewReadResponse(),
}
sr := sqlResourceRead
if req.ResourceVersion > 0 {
// read a specific version
sr = sqlResourceHistoryRead
}
var res *resource.BackendReadResponse
err := b.db.WithTx(ctx, ReadCommittedRO, func(ctx context.Context, tx db.Tx) error {
var err error
res, err = dbutil.QueryRow(ctx, tx, sr, readReq)
res, err = dbutil.QueryRow(ctx, tx, sqlResourceRead, readReq)
return err
})
@@ -745,7 +742,38 @@ func (b *backend) listAtRevision(ctx context.Context, req *resource.ListRequest,
return iter.listRV, err
}
// getHistory fetches the resources from the resource table.
// readHistory fetches the resource history from the resource_history table.
func (b *backend) readHistory(ctx context.Context, key *resource.ResourceKey, rv int64) *resource.BackendReadResponse {
_, span := b.tracer.Start(ctx, tracePrefix+".ReadHistory")
defer span.End()
readReq := &sqlResourceHistoryReadRequest{
SQLTemplate: sqltemplate.New(b.dialect),
Request: &historyReadRequest{
Key: key,
ResourceVersion: rv,
},
Response: NewReadResponse(),
}
var res *resource.BackendReadResponse
err := b.db.WithTx(ctx, ReadCommittedRO, func(ctx context.Context, tx db.Tx) error {
var err error
res, err = dbutil.QueryRow(ctx, tx, sqlResourceHistoryRead, readReq)
return err
})
if errors.Is(err, sql.ErrNoRows) {
return &resource.BackendReadResponse{Error: resource.NewNotFoundError(key)}
}
if err != nil {
return &resource.BackendReadResponse{Error: resource.AsErrorResult(err)}
}
return res
}
// getHistory fetches the resource history from the resource_history table.
func (b *backend) getHistory(ctx context.Context, req *resource.ListRequest, cb func(resource.ListIterator) error) (int64, error) {
ctx, span := b.tracer.Start(ctx, tracePrefix+"getHistory")
defer span.End()
@@ -784,6 +812,9 @@ func (b *backend) getHistory(ctx context.Context, req *resource.ListRequest, cb
listReq.MinRV = req.ResourceVersion
}
// Ignore last deleted history record when listing the trash, using exact matching or not older than matching with a specific RV
useLatestDeletionAsMinRV := listReq.MinRV == 0 && !listReq.Trash && req.VersionMatchV2 != resource.ResourceVersionMatchV2_Exact
err := b.db.WithTx(ctx, ReadCommittedRO, func(ctx context.Context, tx db.Tx) error {
var err error
iter.listRV, err = b.fetchLatestRV(ctx, tx, b.dialect, req.Options.Key.Group, req.Options.Key.Resource)
@@ -791,6 +822,14 @@ func (b *backend) getHistory(ctx context.Context, req *resource.ListRequest, cb
return err
}
if useLatestDeletionAsMinRV {
latestDeletedRV, err := b.fetchLatestHistoryRV(ctx, tx, b.dialect, req.Options.Key, resource.WatchEvent_DELETED)
if err != nil {
return err
}
listReq.MinRV = latestDeletedRV + 1
}
rows, err := dbutil.QueryRows(ctx, tx, sqlResourceHistoryGet, listReq)
if rows != nil {
defer func() {
@@ -860,3 +899,23 @@ func (b *backend) fetchLatestRV(ctx context.Context, x db.ContextExecer, d sqlte
}
return res.ResourceVersion, nil
}
// fetchLatestHistoryRV returns the current maximum RV in the resource_history table
func (b *backend) fetchLatestHistoryRV(ctx context.Context, x db.ContextExecer, d sqltemplate.Dialect, key *resource.ResourceKey, eventType resource.WatchEvent_Type) (int64, error) {
ctx, span := b.tracer.Start(ctx, tracePrefix+"fetchLatestHistoryRV")
defer span.End()
res, err := dbutil.QueryRow(ctx, x, sqlResourceHistoryReadLatestRV, sqlResourceHistoryReadLatestRVRequest{
SQLTemplate: sqltemplate.New(d),
Request: &historyReadLatestRVRequest{
Key: key,
EventType: eventType,
},
Response: new(resourceHistoryReadLatestRVResponse),
})
if errors.Is(err, sql.ErrNoRows) {
return 0, nil
} else if err != nil {
return 0, fmt.Errorf("get resource version: %w", err)
}
return res.ResourceVersion, nil
}