2023-10-07 11:07:38 -04:00
|
|
|
// Copyright (c) 2023 MinIO, Inc.
|
|
|
|
//
|
|
|
|
// This file is part of MinIO Object Storage stack
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Affero General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
package store
|
|
|
|
|
|
|
|
import (
|
2024-09-06 19:06:30 -04:00
|
|
|
"context"
|
2023-10-07 11:07:38 -04:00
|
|
|
"sync"
|
|
|
|
"testing"
|
2024-09-06 19:06:30 -04:00
|
|
|
"time"
|
2023-10-07 11:07:38 -04:00
|
|
|
)
|
|
|
|
|
2024-09-06 19:06:30 -04:00
|
|
|
func TestBatchCommit(t *testing.T) {
|
|
|
|
defer func() {
|
|
|
|
if err := tearDownQueueStore(); err != nil {
|
|
|
|
t.Fatalf("Failed to tear down store; %v", err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
store, err := setUpQueueStore(queueDir, 100)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to create a queue store; %v", err)
|
|
|
|
}
|
|
|
|
|
2023-10-07 11:07:38 -04:00
|
|
|
var limit uint32 = 100
|
2024-09-06 19:06:30 -04:00
|
|
|
|
|
|
|
batch := NewBatch[TestItem](BatchConfig[TestItem]{
|
|
|
|
Limit: limit,
|
|
|
|
Store: store,
|
|
|
|
CommitTimeout: 5 * time.Minute,
|
|
|
|
Log: func(ctx context.Context, err error, id string, errKind ...interface{}) {
|
|
|
|
t.Log(err)
|
|
|
|
},
|
|
|
|
})
|
|
|
|
defer batch.Close()
|
|
|
|
|
2023-10-07 11:07:38 -04:00
|
|
|
for i := 0; i < int(limit); i++ {
|
2024-09-06 19:06:30 -04:00
|
|
|
if err := batch.Add(testItem); err != nil {
|
2023-10-07 11:07:38 -04:00
|
|
|
t.Fatalf("failed to add %v; %v", i, err)
|
|
|
|
}
|
|
|
|
}
|
2024-09-06 19:06:30 -04:00
|
|
|
|
2023-10-07 11:07:38 -04:00
|
|
|
batchLen := batch.Len()
|
|
|
|
if batchLen != int(limit) {
|
2024-09-06 19:06:30 -04:00
|
|
|
t.Fatalf("Expected batch.Len() %v; but got %v", limit, batchLen)
|
2023-10-07 11:07:38 -04:00
|
|
|
}
|
2024-09-06 19:06:30 -04:00
|
|
|
|
|
|
|
keys := store.List()
|
|
|
|
if len(keys) > 0 {
|
|
|
|
t.Fatalf("Expected empty store list but got len(list) %v", len(keys))
|
2023-10-07 11:07:38 -04:00
|
|
|
}
|
2024-09-06 19:06:30 -04:00
|
|
|
if err := batch.Add(testItem); err != nil {
|
|
|
|
t.Fatalf("unable to add to the batch; %v", err)
|
2023-10-07 11:07:38 -04:00
|
|
|
}
|
|
|
|
batchLen = batch.Len()
|
2024-09-06 19:06:30 -04:00
|
|
|
if batchLen != 1 {
|
|
|
|
t.Fatalf("expected batch length to be 1 but got %v", batchLen)
|
2023-10-07 11:07:38 -04:00
|
|
|
}
|
2024-09-06 19:06:30 -04:00
|
|
|
keys = store.List()
|
|
|
|
if len(keys) != 1 {
|
|
|
|
t.Fatalf("expected len(store.List())=1; but got %v", len(keys))
|
2023-10-07 11:07:38 -04:00
|
|
|
}
|
2024-09-06 19:06:30 -04:00
|
|
|
key := keys[0]
|
|
|
|
if !key.Compress {
|
|
|
|
t.Fatal("expected key.Compress=true; but got false")
|
2023-10-07 11:07:38 -04:00
|
|
|
}
|
2024-09-06 19:06:30 -04:00
|
|
|
if key.ItemCount != int(limit) {
|
|
|
|
t.Fatalf("expected key.ItemCount=%d; but got %v", limit, key.ItemCount)
|
|
|
|
}
|
|
|
|
items, err := store.GetMultiple(key)
|
2023-10-07 11:07:38 -04:00
|
|
|
if err != nil {
|
2024-09-06 19:06:30 -04:00
|
|
|
t.Fatalf("unable to read key %v; %v", key.String(), err)
|
2023-10-07 11:07:38 -04:00
|
|
|
}
|
2024-09-06 19:06:30 -04:00
|
|
|
if len(items) != int(limit) {
|
|
|
|
t.Fatalf("expected len(items)=%d; but got %v", limit, len(items))
|
2023-10-07 11:07:38 -04:00
|
|
|
}
|
2024-09-06 19:06:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestBatchCommitOnExit(t *testing.T) {
|
|
|
|
defer func() {
|
|
|
|
if err := tearDownQueueStore(); err != nil {
|
|
|
|
t.Fatalf("Failed to tear down store; %v", err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
store, err := setUpQueueStore(queueDir, 100)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to create a queue store; %v", err)
|
2023-10-07 11:07:38 -04:00
|
|
|
}
|
2024-09-06 19:06:30 -04:00
|
|
|
|
|
|
|
var limit uint32 = 100
|
|
|
|
|
|
|
|
batch := NewBatch[TestItem](BatchConfig[TestItem]{
|
|
|
|
Limit: limit,
|
|
|
|
Store: store,
|
|
|
|
CommitTimeout: 5 * time.Minute,
|
|
|
|
Log: func(ctx context.Context, err error, id string, errKind ...interface{}) {
|
|
|
|
t.Log([]any{err, id, errKind}...)
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
2023-10-07 11:07:38 -04:00
|
|
|
for i := 0; i < int(limit); i++ {
|
2024-09-06 19:06:30 -04:00
|
|
|
if err := batch.Add(testItem); err != nil {
|
|
|
|
t.Fatalf("failed to add %v; %v", i, err)
|
2023-10-07 11:07:38 -04:00
|
|
|
}
|
|
|
|
}
|
2024-09-06 19:06:30 -04:00
|
|
|
|
|
|
|
batch.Close()
|
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
|
|
|
|
batchLen := batch.Len()
|
|
|
|
if batchLen != 0 {
|
|
|
|
t.Fatalf("Expected batch.Len()=0; but got %v", batchLen)
|
|
|
|
}
|
|
|
|
|
|
|
|
keys := store.List()
|
|
|
|
if len(keys) != 1 {
|
|
|
|
t.Fatalf("expected len(store.List())=1; but got %v", len(keys))
|
|
|
|
}
|
|
|
|
|
|
|
|
key := keys[0]
|
|
|
|
if !key.Compress {
|
|
|
|
t.Fatal("expected key.Compress=true; but got false")
|
|
|
|
}
|
|
|
|
if key.ItemCount != int(limit) {
|
|
|
|
t.Fatalf("expected key.ItemCount=%d; but got %v", limit, key.ItemCount)
|
|
|
|
}
|
|
|
|
items, err := store.GetMultiple(key)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to read key %v; %v", key.String(), err)
|
|
|
|
}
|
|
|
|
if len(items) != int(limit) {
|
|
|
|
t.Fatalf("expected len(items)=%d; but got %v", limit, len(items))
|
|
|
|
}
|
2023-10-07 11:07:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestBatchWithConcurrency(t *testing.T) {
|
2024-09-06 19:06:30 -04:00
|
|
|
defer func() {
|
|
|
|
if err := tearDownQueueStore(); err != nil {
|
|
|
|
t.Fatalf("Failed to tear down store; %v", err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
store, err := setUpQueueStore(queueDir, 100)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to create a queue store; %v", err)
|
|
|
|
}
|
|
|
|
|
2023-10-07 11:07:38 -04:00
|
|
|
var limit uint32 = 100
|
2024-09-06 19:06:30 -04:00
|
|
|
|
|
|
|
batch := NewBatch[TestItem](BatchConfig[TestItem]{
|
|
|
|
Limit: limit,
|
|
|
|
Store: store,
|
|
|
|
CommitTimeout: 5 * time.Minute,
|
|
|
|
Log: func(ctx context.Context, err error, id string, errKind ...interface{}) {
|
|
|
|
t.Log(err)
|
|
|
|
},
|
|
|
|
})
|
|
|
|
defer batch.Close()
|
2023-10-07 11:07:38 -04:00
|
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
for i := 0; i < int(limit); i++ {
|
|
|
|
wg.Add(1)
|
2024-09-06 19:06:30 -04:00
|
|
|
go func(key int) {
|
2023-10-07 11:07:38 -04:00
|
|
|
defer wg.Done()
|
2024-09-06 19:06:30 -04:00
|
|
|
if err := batch.Add(testItem); err != nil {
|
|
|
|
t.Errorf("failed to add item %v; %v", key, err)
|
2023-10-07 11:07:38 -04:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}(i)
|
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
|
2024-09-06 19:06:30 -04:00
|
|
|
batchLen := batch.Len()
|
|
|
|
if batchLen != int(limit) {
|
|
|
|
t.Fatalf("Expected batch.Len() %v; but got %v", limit, batchLen)
|
2023-10-07 11:07:38 -04:00
|
|
|
}
|
2024-09-06 19:06:30 -04:00
|
|
|
|
|
|
|
keys := store.List()
|
|
|
|
if len(keys) > 0 {
|
|
|
|
t.Fatalf("Expected empty store list but got len(list) %v", len(keys))
|
2023-10-07 11:07:38 -04:00
|
|
|
}
|
2024-09-06 19:06:30 -04:00
|
|
|
if err := batch.Add(testItem); err != nil {
|
|
|
|
t.Fatalf("unable to add to the batch; %v", err)
|
2023-10-07 11:07:38 -04:00
|
|
|
}
|
2024-09-06 19:06:30 -04:00
|
|
|
batchLen = batch.Len()
|
|
|
|
if batchLen != 1 {
|
|
|
|
t.Fatalf("expected batch length to be 1 but got %v", batchLen)
|
|
|
|
}
|
|
|
|
keys = store.List()
|
|
|
|
if len(keys) != 1 {
|
|
|
|
t.Fatalf("expected len(store.List())=1; but got %v", len(keys))
|
|
|
|
}
|
|
|
|
key := keys[0]
|
|
|
|
if !key.Compress {
|
|
|
|
t.Fatal("expected key.Compress=true; but got false")
|
|
|
|
}
|
|
|
|
if key.ItemCount != int(limit) {
|
|
|
|
t.Fatalf("expected key.ItemCount=%d; but got %v", limit, key.ItemCount)
|
|
|
|
}
|
|
|
|
items, err := store.GetMultiple(key)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to read key %v; %v", key.String(), err)
|
|
|
|
}
|
|
|
|
if len(items) != int(limit) {
|
|
|
|
t.Fatalf("expected len(items)=%d; but got %v", limit, len(items))
|
2023-10-07 11:07:38 -04:00
|
|
|
}
|
|
|
|
}
|