filer: keep the internal .system folder out of the per-bucket store path (#10248)

* filer: keep .system internal folder in the default SQL table

Bucket-table SQL stores read the first path segment under /buckets as a
bucket name. The ListBuckets owner index lives at /buckets/.system/..., so
every write there hit isValidBucket(".system") == false and returned
"invalid bucket name .system", flooding the filer log on the postgres/mysql
backends. Route dot-prefixed internal folders to the default table by their
full path, like any other non-bucket entry.

* filer: keep .system internal folder in the default leveldb3 DB

Same guard as the SQL stores: leveldb3 would otherwise open a separate DB
for the .system owner-index folder instead of keeping it in the default DB.

* filer: keep .system internal folder under the default ydb prefix

Skips a DescribeTable round trip per operation on the .system owner-index
path, which never resolves to a real bucket table.

* filer: keep .system internal folder in the default arangodb collection

Avoids creating a stray collection for the .system owner-index folder.
This commit is contained in:
Chris Lu
2026-07-06 11:25:50 -07:00
committed by GitHub
parent e98cbfc8f1
commit 6e477ae00f
5 changed files with 79 additions and 0 deletions
@@ -129,6 +129,14 @@ func (store *AbstractSqlStore) getTxOrDB(ctx context.Context, fullpath util.Full
shortPath = util.FullPath(bucketAndObjectKey[t:])
}
// Dot-prefixed entries directly under /buckets (e.g. .system) are internal
// folders, not S3 buckets; keep them in the default table by full path.
if strings.HasPrefix(bucket, ".") {
bucket = DEFAULT_TABLE
shortPath = fullpath
return
}
if isValidBucket(bucket) {
store.dbsLock.Lock()
defer store.dbsLock.Unlock()
@@ -0,0 +1,53 @@
package abstract_sql
import (
"context"
"testing"
"github.com/seaweedfs/seaweedfs/weed/util"
)
// The bucket owner index lives at /buckets/.system/owners/<owner>/<bucket>.
// .system is an internal folder, not an S3 bucket, so getTxOrDB must route it
// to the default table rather than reject it as an invalid bucket name.
func TestGetTxOrDBInternalSystemFolder(t *testing.T) {
store := &AbstractSqlStore{SupportBucketTable: true}
ctx := context.Background()
cases := []struct {
path string
isForChildren bool
}{
{"/buckets/.system/owners", false},
{"/buckets/.system/owners/foo/bucket1", false},
{"/buckets/.system/owners/foo", true},
}
for _, c := range cases {
_, bucket, shortPath, err := store.getTxOrDB(ctx, util.FullPath(c.path), c.isForChildren)
if err != nil {
t.Errorf("getTxOrDB(%s): unexpected error: %v", c.path, err)
}
if bucket != DEFAULT_TABLE {
t.Errorf("getTxOrDB(%s): bucket = %q, want %q", c.path, bucket, DEFAULT_TABLE)
}
if string(shortPath) != c.path {
t.Errorf("getTxOrDB(%s): shortPath = %q, want %q", c.path, shortPath, c.path)
}
}
}
func TestGetTxOrDBRealBucket(t *testing.T) {
store := &AbstractSqlStore{SupportBucketTable: true, dbs: map[string]bool{"mybucket": true}}
ctx := context.Background()
_, bucket, shortPath, err := store.getTxOrDB(ctx, util.FullPath("/buckets/mybucket/dir/file.txt"), false)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if bucket != "mybucket" {
t.Errorf("bucket = %q, want mybucket", bucket)
}
if string(shortPath) != "/dir/file.txt" {
t.Errorf("shortPath = %q, want /dir/file.txt", shortPath)
}
}
+5
View File
@@ -77,6 +77,11 @@ func extractBucket(fullpath util.FullPath) (string, string) {
bucket = bucketAndObjectKey[:t]
shortPath = string(util.FullPath(bucketAndObjectKey[t:]))
}
// Dot-prefixed entries directly under /buckets (e.g. .system) are internal
// folders, not S3 buckets; keep them in the default collection.
if strings.HasPrefix(bucket, ".") {
return "", string(fullpath)
}
return bucket, shortPath
}
+7
View File
@@ -118,6 +118,13 @@ func (store *LevelDB3Store) findDB(fullpath weed_util.FullPath, isForChildren bo
shortPath = weed_util.FullPath(bucketAndObjectKey[t:])
}
// Dot-prefixed entries directly under /buckets (e.g. .system) are internal
// folders, not S3 buckets; keep them in the default DB by full path.
if strings.HasPrefix(bucket, ".") {
store.dbsLock.RUnlock()
return defaultDB, DEFAULT, fullpath, nil
}
if db, found := store.dbs[bucket]; found {
store.dbsLock.RUnlock()
return db, bucket, shortPath, nil
+6
View File
@@ -468,6 +468,12 @@ func (store *YdbStore) getPrefix(ctx context.Context, dir *string) (tablePathPre
return
}
// Dot-prefixed entries directly under /buckets (e.g. .system) are internal
// folders, not S3 buckets; keep them under the default prefix.
if strings.HasPrefix(bucket, ".") {
return
}
store.dbsLock.Lock()
defer store.dbsLock.Unlock()