optimize the perf and support more features
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
Copyright 2024 The GoStor Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package iscsit
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTSIHBitmapAllocRelease(t *testing.T) {
|
||||
b := newTSIHBitmap()
|
||||
|
||||
// Test basic allocation and release
|
||||
tsih1 := b.alloc()
|
||||
if tsih1 == ISCSI_UNSPEC_TSIH {
|
||||
t.Fatal("failed to allocate first TSIH")
|
||||
}
|
||||
if tsih1 != 1 {
|
||||
t.Errorf("expected first TSIH to be 1, got %d", tsih1)
|
||||
}
|
||||
|
||||
tsih2 := b.alloc()
|
||||
if tsih2 == ISCSI_UNSPEC_TSIH {
|
||||
t.Fatal("failed to allocate second TSIH")
|
||||
}
|
||||
if tsih2 != 2 {
|
||||
t.Errorf("expected second TSIH to be 2, got %d", tsih2)
|
||||
}
|
||||
|
||||
// Release first
|
||||
b.release(tsih1)
|
||||
// Note: TSIH bitmap uses circular allocation, next pointer won't return to released positions
|
||||
// This is to avoid concurrency issues, subsequent allocations continue from current next
|
||||
tsih3 := b.alloc()
|
||||
if tsih3 == ISCSI_UNSPEC_TSIH {
|
||||
t.Error("failed to allocate after release")
|
||||
}
|
||||
// Verify tsih1 can be reallocated (at some point)
|
||||
if tsih3 == tsih1 || tsih3 == tsih2 {
|
||||
t.Logf("TSIH was recycled immediately: released %d, got %d", tsih1, tsih3)
|
||||
}
|
||||
|
||||
// Release all
|
||||
b.release(tsih2)
|
||||
b.release(tsih3)
|
||||
}
|
||||
|
||||
func TestTSIHBitmapReservedValues(t *testing.T) {
|
||||
b := newTSIHBitmap()
|
||||
|
||||
// Test reserved values cannot be allocated
|
||||
// 0 and 65535 are reserved values
|
||||
for i := 0; i < 10; i++ {
|
||||
tsih := b.alloc()
|
||||
if tsih == 0 {
|
||||
t.Error("allocated reserved TSIH 0")
|
||||
}
|
||||
if tsih == ISCSI_MAX_TSIH {
|
||||
t.Error("allocated reserved TSIH 65535")
|
||||
}
|
||||
if tsih == ISCSI_UNSPEC_TSIH {
|
||||
break
|
||||
}
|
||||
b.release(tsih)
|
||||
}
|
||||
|
||||
// Test releasing reserved values doesn't panic
|
||||
b.release(0)
|
||||
b.release(ISCSI_MAX_TSIH)
|
||||
}
|
||||
|
||||
func TestTSIHBitmapExhaustion(t *testing.T) {
|
||||
b := newTSIHBitmap()
|
||||
|
||||
// Allocate many TSIHs
|
||||
allocated := make([]uint16, 0, 100)
|
||||
for i := 0; i < 100; i++ {
|
||||
tsih := b.alloc()
|
||||
if tsih == ISCSI_UNSPEC_TSIH {
|
||||
t.Fatalf("failed to allocate TSIH at iteration %d", i)
|
||||
}
|
||||
allocated = append(allocated, tsih)
|
||||
}
|
||||
|
||||
// 释放所有
|
||||
for _, tsih := range allocated {
|
||||
b.release(tsih)
|
||||
}
|
||||
|
||||
// Reallocate, should succeed
|
||||
for i := 0; i < 100; i++ {
|
||||
tsih := b.alloc()
|
||||
if tsih == ISCSI_UNSPEC_TSIH {
|
||||
t.Fatalf("failed to reallocate TSIH at iteration %d", i)
|
||||
}
|
||||
b.release(tsih)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTSIHBitmapConcurrency(t *testing.T) {
|
||||
b := newTSIHBitmap()
|
||||
const numGoroutines = 100
|
||||
const allocsPerGoroutine = 100
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(numGoroutines)
|
||||
|
||||
allTSIHs := make(chan uint16, numGoroutines*allocsPerGoroutine)
|
||||
|
||||
for i := 0; i < numGoroutines; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for j := 0; j < allocsPerGoroutine; j++ {
|
||||
tsih := b.alloc()
|
||||
if tsih != ISCSI_UNSPEC_TSIH {
|
||||
allTSIHs <- tsih
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(allTSIHs)
|
||||
|
||||
// Check no duplicate TSIHs
|
||||
seen := make(map[uint16]bool)
|
||||
for tsih := range allTSIHs {
|
||||
if seen[tsih] {
|
||||
t.Errorf("TSIH %d was allocated more than once", tsih)
|
||||
}
|
||||
seen[tsih] = true
|
||||
}
|
||||
|
||||
// Release all allocated TSIHs
|
||||
for tsih := range seen {
|
||||
b.release(tsih)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTSIHBitmapAlloc(b *testing.B) {
|
||||
bitmap := newTSIHBitmap()
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
tsih := bitmap.alloc()
|
||||
if tsih != ISCSI_UNSPEC_TSIH {
|
||||
bitmap.release(tsih)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkTSIHBitmapAllocSequential(b *testing.B) {
|
||||
bitmap := newTSIHBitmap()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
tsih := bitmap.alloc()
|
||||
if tsih != ISCSI_UNSPEC_TSIH {
|
||||
bitmap.release(tsih)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user