mirror of
https://github.com/pgsty/minio.git
synced 2026-09-08 11:34:04 +03:00
7a060cab1e
Keep NVMe/HDD pool pairs useful without remote tiering: promote objects that are read often, demote previously moved objects once they go idle, and leave the feature off until operators set a two-pool topology. Signed-off-by: mr javad seydi <seydi.birjand@gmail.com>
96 lines
2.7 KiB
Go
96 lines
2.7 KiB
Go
// Copyright (c) 2015-2026 MinIO, Inc.
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"math"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/minio/minio/internal/config/ilm"
|
|
)
|
|
|
|
func TestAccessEntryRollAndHits(t *testing.T) {
|
|
entry := accessEntry{Bins: []uint32{3, 2, 1}, HeadAt: 100, LastAt: 107}
|
|
entry.rollTo(120, 10, 3)
|
|
want := []uint32{0, 0, 3}
|
|
for i := range want {
|
|
if entry.Bins[i] != want[i] {
|
|
t.Fatalf("bins = %v, want %v", entry.Bins, want)
|
|
}
|
|
}
|
|
if entry.HeadAt != 120 || entry.LastAt != 107 {
|
|
t.Fatalf("head/last = %d/%d", entry.HeadAt, entry.LastAt)
|
|
}
|
|
|
|
entry = accessEntry{Bins: []uint32{10, 20, 30}, HeadAt: 120}
|
|
if got := entry.hits(20*time.Second, 10); got != 30 {
|
|
t.Fatalf("20s hits = %d, want 30", got)
|
|
}
|
|
if got := entry.hits(21*time.Second, 10); got != 60 {
|
|
t.Fatalf("21s hits = %d, want 60", got)
|
|
}
|
|
entry.rollTo(200, 10, 3)
|
|
if got := entry.total(); got != 0 {
|
|
t.Fatalf("expired total = %d, want 0", got)
|
|
}
|
|
}
|
|
|
|
func TestAccessEntryMergeSaturates(t *testing.T) {
|
|
entry := accessEntry{Bins: []uint32{math.MaxUint32 - 1}}
|
|
entry.mergeFrom(accessEntry{Bins: []uint32{10}, LastAt: 50})
|
|
if entry.Bins[0] != math.MaxUint32 || entry.LastAt != 50 {
|
|
t.Fatalf("merged entry = %+v", entry)
|
|
}
|
|
}
|
|
|
|
func TestAccessTrackerEvictsColdest(t *testing.T) {
|
|
tracker := newAccessTracker()
|
|
live := map[string]accessEntry{
|
|
"a": {Bins: []uint32{1}, HeadAt: 100},
|
|
"b": {Bins: []uint32{5}, HeadAt: 100},
|
|
"c": {Bins: []uint32{3}, HeadAt: 100},
|
|
}
|
|
tracker.evict(live, 100, 10, ilm.Config{AccessBins: 1, AccessMaxTracked: 2})
|
|
if len(live) != 2 {
|
|
t.Fatalf("len = %d, want 2", len(live))
|
|
}
|
|
if _, ok := live["a"]; ok {
|
|
t.Fatal("coldest entry was retained")
|
|
}
|
|
}
|
|
|
|
func TestAccessKeyRoundTrip(t *testing.T) {
|
|
key := accessKey("bucket", "a/b/c")
|
|
bucket, object, ok := splitAccessKey(key)
|
|
if !ok || bucket != "bucket" || object != "a/b/c" {
|
|
t.Fatalf("split %q = %q/%q/%v", key, bucket, object, ok)
|
|
}
|
|
}
|
|
|
|
func TestAccessShardFresh(t *testing.T) {
|
|
const now = int64(1000)
|
|
if !accessShardFresh(now, accessShard{UpdatedAt: 950}, 100) {
|
|
t.Fatal("fresh shard rejected")
|
|
}
|
|
if accessShardFresh(now, accessShard{UpdatedAt: 899}, 100) {
|
|
t.Fatal("stale shard accepted")
|
|
}
|
|
if accessShardFresh(now, accessShard{UpdatedAt: 1101}, 100) {
|
|
t.Fatal("far-future shard accepted")
|
|
}
|
|
if accessShardFresh(now, accessShard{}, 100) {
|
|
t.Fatal("zero timestamp accepted")
|
|
}
|
|
}
|
|
|
|
func TestAccessTrackerRestoresDemoteCandidates(t *testing.T) {
|
|
tracker := newAccessTracker()
|
|
candidate := demoteCandidate{Bucket: "bucket", Object: "object", Pool: 1}
|
|
tracker.restoreDemoteCandidates([]demoteCandidate{candidate})
|
|
got := tracker.takeDemoteCandidates()
|
|
if len(got) != 1 || got[0] != candidate {
|
|
t.Fatalf("restored candidates = %+v, want %+v", got, candidate)
|
|
}
|
|
}
|