From 8311221fb4b2324d07e0d7c8c7deab9cb63f36b4 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Thu, 22 Oct 2026 03:14:14 -0700 Subject: [PATCH] filer.conf: match inode_index scope on path boundaries inodeIndexInScope used MatchStorageRule's raw prefix match, so a rule on /exports also indexed entries under /exports2 and /exports_old. MatchInodeIndexRule requires the rule location to end at a '/' boundary, and InodeIndexActiveUnder now uses the same check for its own-coverage branch. --- weed/filer/filer_conf.go | 21 ++++++++++++++++++++- weed/filer/filer_inode_index.go | 2 +- weed/filer/filer_inode_index_test.go | 13 +++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/weed/filer/filer_conf.go b/weed/filer/filer_conf.go index ed53cbca98..f6ca74a053 100644 --- a/weed/filer/filer_conf.go +++ b/weed/filer/filer_conf.go @@ -252,11 +252,30 @@ func ClonePathConf(src *filer_pb.FilerConf_PathConf) *filer_pb.FilerConf_PathCon } } +// MatchInodeIndexRule reports whether an inode_index rule covers path. Unlike +// MatchStorageRule it requires the rule's location to end at a path boundary, +// so a rule on /exports does not index /exports2 or /exports_old. +func (fc *FilerConf) MatchInodeIndexRule(path string) bool { + active := false + fc.rules.MatchPrefix([]byte(path), func(key []byte, value *filer_pb.FilerConf_PathConf) bool { + if !value.InodeIndex { + return true + } + rulePath := strings.TrimSuffix(string(key), "/") + if path == rulePath || strings.HasPrefix(path, rulePath+"/") { + active = true + return false + } + return true + }) + return active +} + // InodeIndexActiveUnder reports whether entries inside dirPath may carry inode // index rows: either dirPath itself is covered by an inode_index rule, or such // a rule applies to a subtree inside dirPath. func (fc *FilerConf) InodeIndexActiveUnder(dirPath string) bool { - if fc.MatchStorageRule(dirPath).InodeIndex { + if fc.MatchInodeIndexRule(dirPath) { return true } prefix := dirPath diff --git a/weed/filer/filer_inode_index.go b/weed/filer/filer_inode_index.go index d1a6b4fa21..5ea81f0ba0 100644 --- a/weed/filer/filer_inode_index.go +++ b/weed/filer/filer_inode_index.go @@ -164,7 +164,7 @@ func (fsw *FilerStoreWrapper) inodeIndexInScope(path util.FullPath) bool { if fc == nil { return false } - return fc.MatchStorageRule(string(path)).InodeIndex + return fc.MatchInodeIndexRule(string(path)) } // inodeIndexUnder reports whether any entry inside dirPath may carry an inode diff --git a/weed/filer/filer_inode_index_test.go b/weed/filer/filer_inode_index_test.go index 034c1fd3ec..a28ef0cbb6 100644 --- a/weed/filer/filer_inode_index_test.go +++ b/weed/filer/filer_inode_index_test.go @@ -301,3 +301,16 @@ func TestInodeIndexActiveUnder(t *testing.T) { assert.False(t, NewFilerConf().InodeIndexActiveUnder("/")) } + +func TestMatchInodeIndexRule(t *testing.T) { + fc := inodeIndexConf("/exports") + assert.True(t, fc.MatchInodeIndexRule("/exports")) + assert.True(t, fc.MatchInodeIndexRule("/exports/sub/file")) + assert.False(t, fc.MatchInodeIndexRule("/exports2")) + assert.False(t, fc.MatchInodeIndexRule("/exports_old/x")) + assert.False(t, fc.MatchInodeIndexRule("/exp")) + assert.False(t, fc.MatchInodeIndexRule("/other")) + + assert.True(t, inodeIndexConf("/").MatchInodeIndexRule("/anything")) + assert.False(t, NewFilerConf().MatchInodeIndexRule("/exports")) +}