s3tables: fix pagination and enhance error handling in list/delete operations
- Fix InclusiveStartFrom logic to ensure exclusive start on continued pages - Prevent duplicates in bucket, namespace, and table listings - Fail fast on listing errors during bucket and namespace deletion - Stop swallowing errors in handleListTables and return proper HTTP error responses
This commit is contained in:
@@ -85,7 +85,7 @@ func (h *S3TablesHandler) handleListTableBuckets(w http.ResponseWriter, r *http.
|
|||||||
Directory: TablesPath,
|
Directory: TablesPath,
|
||||||
Limit: uint32(maxBuckets * 2), // Fetch more than needed to account for filtering
|
Limit: uint32(maxBuckets * 2), // Fetch more than needed to account for filtering
|
||||||
StartFromFileName: lastFileName,
|
StartFromFileName: lastFileName,
|
||||||
InclusiveStartFrom: lastFileName != "",
|
InclusiveStartFrom: lastFileName == "",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -216,6 +216,13 @@ func (h *S3TablesHandler) handleDeleteTableBucket(w http.ResponseWriter, r *http
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if !errors.Is(err, ErrNotFound) {
|
||||||
|
h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, fmt.Sprintf("failed to list bucket entries: %v", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if hasChildren {
|
if hasChildren {
|
||||||
h.writeError(w, http.StatusConflict, ErrCodeBucketNotEmpty, "table bucket is not empty")
|
h.writeError(w, http.StatusConflict, ErrCodeBucketNotEmpty, "table bucket is not empty")
|
||||||
return fmt.Errorf("bucket not empty")
|
return fmt.Errorf("bucket not empty")
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package s3tables
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -197,7 +198,7 @@ func (h *S3TablesHandler) handleListNamespaces(w http.ResponseWriter, r *http.Re
|
|||||||
Directory: bucketPath,
|
Directory: bucketPath,
|
||||||
Limit: uint32(maxNamespaces * 2),
|
Limit: uint32(maxNamespaces * 2),
|
||||||
StartFromFileName: lastFileName,
|
StartFromFileName: lastFileName,
|
||||||
InclusiveStartFrom: lastFileName != "",
|
InclusiveStartFrom: lastFileName == "",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -319,6 +320,13 @@ func (h *S3TablesHandler) handleDeleteNamespace(w http.ResponseWriter, r *http.R
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if !errors.Is(err, ErrNotFound) {
|
||||||
|
h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, fmt.Sprintf("failed to list namespace entries: %v", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if hasChildren {
|
if hasChildren {
|
||||||
h.writeError(w, http.StatusConflict, ErrCodeNamespaceNotEmpty, "namespace is not empty")
|
h.writeError(w, http.StatusConflict, ErrCodeNamespaceNotEmpty, "namespace is not empty")
|
||||||
return fmt.Errorf("namespace not empty")
|
return fmt.Errorf("namespace not empty")
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ func (h *S3TablesHandler) handleCreateTable(w http.ResponseWriter, r *http.Reque
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tableARN := h.generateTableARN(bucketName, namespaceName, req.Name)
|
tableARN := h.generateTableARN(bucketName, namespaceName+"/"+req.Name)
|
||||||
|
|
||||||
resp := &CreateTableResponse{
|
resp := &CreateTableResponse{
|
||||||
TableARN: tableARN,
|
TableARN: tableARN,
|
||||||
@@ -206,7 +206,7 @@ func (h *S3TablesHandler) handleGetTable(w http.ResponseWriter, r *http.Request,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tableARN := h.generateTableARN(bucketName, namespace, tableName)
|
tableARN := h.generateTableARN(bucketName, namespace+"/"+tableName)
|
||||||
|
|
||||||
resp := &GetTableResponse{
|
resp := &GetTableResponse{
|
||||||
Name: metadata.Name,
|
Name: metadata.Name,
|
||||||
@@ -266,7 +266,8 @@ func (h *S3TablesHandler) handleListTables(w http.ResponseWriter, r *http.Reques
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tables = []TableSummary{}
|
h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, fmt.Sprintf("failed to list tables: %v", err))
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := &ListTablesResponse{
|
resp := &ListTablesResponse{
|
||||||
@@ -286,7 +287,7 @@ func (h *S3TablesHandler) listTablesInNamespaceWithClient(ctx context.Context, c
|
|||||||
Directory: namespacePath,
|
Directory: namespacePath,
|
||||||
Limit: uint32(maxTables * 2),
|
Limit: uint32(maxTables * 2),
|
||||||
StartFromFileName: lastFileName,
|
StartFromFileName: lastFileName,
|
||||||
InclusiveStartFrom: lastFileName != "",
|
InclusiveStartFrom: lastFileName == "",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -326,7 +327,7 @@ func (h *S3TablesHandler) listTablesInNamespaceWithClient(ctx context.Context, c
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
tableARN := h.generateTableARN(bucketName, namespace, entry.Entry.Name)
|
tableARN := h.generateTableARN(bucketName, namespace+"/"+entry.Entry.Name)
|
||||||
|
|
||||||
*tables = append(*tables, TableSummary{
|
*tables = append(*tables, TableSummary{
|
||||||
Name: metadata.Name,
|
Name: metadata.Name,
|
||||||
@@ -360,7 +361,7 @@ func (h *S3TablesHandler) listTablesInAllNamespaces(ctx context.Context, filerCl
|
|||||||
Directory: bucketPath,
|
Directory: bucketPath,
|
||||||
Limit: 100,
|
Limit: 100,
|
||||||
StartFromFileName: lastFileName,
|
StartFromFileName: lastFileName,
|
||||||
InclusiveStartFrom: lastFileName != "",
|
InclusiveStartFrom: lastFileName == "",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
Reference in New Issue
Block a user