Files
seaweedfs/weed/filer/read_write_test.go
T
Chris Lu eafe79ebff filer: skip UpdateEntry when inline content is unchanged (#11580)
* filer: skip UpdateEntry when inline content is unchanged

SaveInsideFiler rewrites config files (IAM identities, filer.conf,
remote mappings, policies) unconditionally. Each no-op UpdateEntry is a
metadata event the local meta log persists to /topics/.system/log,
which appends a chunk to a volume. A client that rewrites identical
config on a timer, e.g. the seaweedfs-operator 5-minute resync calling
UpdateUser with unchanged actions, keeps .dat/.idx files growing on an
otherwise idle cluster and prevents HDD spindown
(seaweedfs/seaweedfs#11571).

Skip the UpdateEntry when the stored inline content is byte-identical,
so unchanged writes produce no metadata event and no volume writes.

* filer: test that identical SaveInsideFiler writes skip UpdateEntry

* filer: require stamped Md5 before skipping identical writes

An entry holding identical content but no Md5 (written before hashing,
or by a tool that cleared it) would never get the stamp that
IF_ETAG_MATCH conditional writes key off. Skip only when both the
stored content and its Md5 match, so one write still lands to repair
the stamp.
2026-10-03 21:00:51 +08:00

52 lines
1.9 KiB
Go

package filer
import (
"context"
"testing"
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// Rewriting identical inline content must not issue UpdateEntry: each one is a
// metadata event the local meta log persists to /topics/.system/log, and a
// client that rewrites the same config on a timer (e.g. the operator's 5-minute
// resync) keeps the volumes growing on an otherwise idle cluster.
func TestSaveInsideFilerSkipsIdenticalContent(t *testing.T) {
ctx := context.Background()
client := newFakeFilerConfClient()
require.NoError(t, SaveInsideFiler(ctx, client, DirectoryEtcSeaweedFS, "a.json", []byte("v1")))
require.Equal(t, 0, client.updateCalls)
require.NoError(t, SaveInsideFiler(ctx, client, DirectoryEtcSeaweedFS, "a.json", []byte("v1")))
assert.Equal(t, 0, client.updateCalls)
require.NoError(t, SaveInsideFiler(ctx, client, DirectoryEtcSeaweedFS, "a.json", []byte("v2")))
assert.Equal(t, 1, client.updateCalls)
content, err := ReadInsideFiler(ctx, client, DirectoryEtcSeaweedFS, "a.json")
require.NoError(t, err)
assert.Equal(t, []byte("v2"), content)
}
// A legacy entry holding identical bytes but no Md5 still gets one write to
// stamp the hash that IF_ETAG_MATCH conditional writes key off; later
// identical writes skip.
func TestSaveInsideFilerStampsMd5OnLegacyEntry(t *testing.T) {
ctx := context.Background()
client := newFakeFilerConfClient()
client.entries[client.key(DirectoryEtcSeaweedFS, "b.json")] = &filer_pb.Entry{
Name: "b.json",
Content: []byte("v1"),
Attributes: &filer_pb.FuseAttributes{},
}
require.NoError(t, SaveInsideFiler(ctx, client, DirectoryEtcSeaweedFS, "b.json", []byte("v1")))
assert.Equal(t, 1, client.updateCalls)
require.NoError(t, SaveInsideFiler(ctx, client, DirectoryEtcSeaweedFS, "b.json", []byte("v1")))
assert.Equal(t, 1, client.updateCalls)
}