filer: mark a store transaction independently of the store's own key

ArangoDB and FoundationDB keep their transaction under other context
keys, so the CreateEntry guard keyed on "tx" missed them. The filer now
marks every context returned by BeginTransaction and the guard checks
that marker.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chris LuandClaude Opus 5.5 committed 2026-11-05 23:52:07 -08:00
1 parent b7dfff6616
commit bd0505eb80
2 files changed
+16 -9

No files matched your search

+13 -7
View File
@@ -451,8 +451,16 @@ func (fs *Filer) GetMaster(ctx context.Context) pb.ServerAddress {
return fs.MasterClient.GetMaster(ctx)
}
// storeTransactionKey marks a context inside BeginTransaction, whatever key
// the store keeps its own transaction under.
type storeTransactionKey struct{}
func (f *Filer) BeginTransaction(ctx context.Context) (context.Context, error) {
return f.Store.BeginTransaction(ctx)
txCtx, err := f.Store.BeginTransaction(ctx)
if err != nil {
return txCtx, err
}
return context.WithValue(txCtx, storeTransactionKey{}, true), nil
}
func (f *Filer) CommitTransaction(ctx context.Context) error {
@@ -516,13 +524,11 @@ func (f *Filer) CreateEntry(ctx context.Context, entry *Entry, existing *Entry,
oldEntry := existing
if oldEntry == nil {
var findErr error
// Inside a store transaction the lookup must not run the lazy remote
// fetch: the fetch persists on a second connection, which waits on
// the row lock this transaction holds when it deleted the path (a
// rename onto an existing target). The create writes the path either
// way; reads inside the transaction keep the fetch.
// A lazy fetch here would persist outside the transaction and wait on
// the lock it holds for a target it just deleted; the create writes
// the path either way.
findCtx := ctx
if ctx.Value("tx") != nil {
if ctx.Value(storeTransactionKey{}) != nil {
findCtx = context.WithValue(ctx, lazyFetchContextKey{}, true)
}
oldEntry, findErr = f.FindEntry(findCtx, entry.FullPath)
+3 -2
View File
@@ -743,8 +743,9 @@ func TestCreateEntry_SkipsTheLazyFetchInsideAStoreTransaction(t *testing.T) {
}
f, store := newMountedTestFiler(t, storageType, countingStub, 0)
putDirEntry(store, "/buckets/mybucket/dir")
// the key a store transaction travels under (abstract_sql getTxOrDB)
txCtx := context.WithValue(context.Background(), "tx", struct{}{})
// the stub opens no transaction of its own; the filer marks it anyway
txCtx, err := f.BeginTransaction(context.Background())
require.NoError(t, err)
// a create inside the transaction: its lookup does not consult the
// remote, the entry is inserted as given