Browse Source
feat: drop table location mapping support (#8458)
feat: drop table location mapping support (#8458)
* feat: drop table location mapping support Disable external metadata locations for S3 Tables and remove the table location mapping index entirely. Table metadata must live under the table bucket paths, so lookups no longer use mapping directories. Changes: - Remove mapping lookup and cache from bucket path resolution - Reject metadataLocation in CreateTable and UpdateTable - Remove mapping helpers and tests * compile * refactor * fix: accept metadataLocation in S3 Tables API requests We removed the external table location mapping feature, but still need to accept and store metadataLocation values from clients like Trino. The mapping feature was an internal implementation detail that mapped external buckets to internal table paths. The metadataLocation field itself is part of the S3 Tables API and should be preserved. * fmt * fix: handle MetadataLocation in UpdateTable requests Mirror handleCreateTable behavior by updating metadata.MetadataLocation when req.MetadataLocation is provided in UpdateTable requests. This ensures table metadata location can be updated, not just set during creation.pull/8454/merge
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 50 additions and 483 deletions
-
82weed/s3api/auth_proxy_integration_test.go
-
10weed/s3api/auth_security_test.go
-
17weed/s3api/bucket_metadata.go
-
129weed/s3api/bucket_paths.go
-
45weed/s3api/bucket_paths_test.go
-
116weed/s3api/s3tables/handler_table.go
-
77weed/s3api/s3tables/table_location_mapping_test.go
-
57weed/s3api/s3tables/utils.go
@ -1,45 +0,0 @@ |
|||
package s3api |
|||
|
|||
import "testing" |
|||
|
|||
func TestNormalizeTableLocationMappingPath(t *testing.T) { |
|||
testCases := []struct { |
|||
name string |
|||
raw string |
|||
want string |
|||
}{ |
|||
{ |
|||
name: "legacy table path maps to bucket root", |
|||
raw: "/buckets/warehouse/analytics/orders", |
|||
want: "/buckets/warehouse", |
|||
}, |
|||
{ |
|||
name: "already bucket root", |
|||
raw: "/buckets/warehouse", |
|||
want: "/buckets/warehouse", |
|||
}, |
|||
{ |
|||
name: "relative buckets path normalized and reduced", |
|||
raw: "buckets/warehouse/analytics/orders", |
|||
want: "/buckets/warehouse", |
|||
}, |
|||
{ |
|||
name: "non buckets path preserved", |
|||
raw: "/tmp/custom/path", |
|||
want: "/tmp/custom/path", |
|||
}, |
|||
{ |
|||
name: "empty path", |
|||
raw: "", |
|||
want: "", |
|||
}, |
|||
} |
|||
|
|||
for _, tc := range testCases { |
|||
t.Run(tc.name, func(t *testing.T) { |
|||
if got := normalizeTableLocationMappingPath(tc.raw); got != tc.want { |
|||
t.Fatalf("normalizeTableLocationMappingPath(%q)=%q, want %q", tc.raw, got, tc.want) |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
@ -1,77 +0,0 @@ |
|||
package s3tables |
|||
|
|||
import ( |
|||
"strings" |
|||
"testing" |
|||
) |
|||
|
|||
func TestGetTableLocationMappingEntryPathPerTable(t *testing.T) { |
|||
tableLocationBucket := "shared-location--table-s3" |
|||
tablePathA := GetTablePath("warehouse", "analytics", "orders") |
|||
tablePathB := GetTablePath("warehouse", "analytics", "customers") |
|||
|
|||
entryPathA := GetTableLocationMappingEntryPath(tableLocationBucket, tablePathA) |
|||
entryPathARepeat := GetTableLocationMappingEntryPath(tableLocationBucket, tablePathA) |
|||
entryPathB := GetTableLocationMappingEntryPath(tableLocationBucket, tablePathB) |
|||
|
|||
if entryPathA != entryPathARepeat { |
|||
t.Fatalf("mapping entry path should be deterministic: %q != %q", entryPathA, entryPathARepeat) |
|||
} |
|||
if entryPathA == entryPathB { |
|||
t.Fatalf("mapping entry path should differ per table path: %q == %q", entryPathA, entryPathB) |
|||
} |
|||
|
|||
expectedPrefix := GetTableLocationMappingPath(tableLocationBucket) + "/" |
|||
if !strings.HasPrefix(entryPathA, expectedPrefix) { |
|||
t.Fatalf("mapping entry path %q should start with %q", entryPathA, expectedPrefix) |
|||
} |
|||
if strings.TrimPrefix(entryPathA, expectedPrefix) == "" { |
|||
t.Fatalf("mapping entry name should not be empty: %q", entryPathA) |
|||
} |
|||
} |
|||
|
|||
func TestTableBucketPathFromTablePath(t *testing.T) { |
|||
testCases := []struct { |
|||
name string |
|||
tablePath string |
|||
expected string |
|||
ok bool |
|||
}{ |
|||
{ |
|||
name: "valid table path", |
|||
tablePath: GetTablePath("warehouse", "analytics", "orders"), |
|||
expected: GetTableBucketPath("warehouse"), |
|||
ok: true, |
|||
}, |
|||
{ |
|||
name: "valid table bucket root", |
|||
tablePath: GetTableBucketPath("warehouse"), |
|||
expected: GetTableBucketPath("warehouse"), |
|||
ok: true, |
|||
}, |
|||
{ |
|||
name: "invalid non-tables path", |
|||
tablePath: "/tmp/warehouse/analytics/orders", |
|||
expected: "", |
|||
ok: false, |
|||
}, |
|||
{ |
|||
name: "invalid empty bucket segment", |
|||
tablePath: "/buckets/", |
|||
expected: "", |
|||
ok: false, |
|||
}, |
|||
} |
|||
|
|||
for _, tc := range testCases { |
|||
t.Run(tc.name, func(t *testing.T) { |
|||
actual, ok := tableBucketPathFromTablePath(tc.tablePath) |
|||
if ok != tc.ok { |
|||
t.Fatalf("tableBucketPathFromTablePath(%q) ok=%v, want %v", tc.tablePath, ok, tc.ok) |
|||
} |
|||
if actual != tc.expected { |
|||
t.Fatalf("tableBucketPathFromTablePath(%q)=%q, want %q", tc.tablePath, actual, tc.expected) |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue