177 lines
3.9 KiB
Go
177 lines
3.9 KiB
Go
/*
|
|
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)
|
|
}
|
|
}
|
|
}
|