You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

215 lines
6.3 KiB

package topology
import (
"sync"
"testing"
"time"
"github.com/seaweedfs/seaweedfs/weed/storage/types"
)
func TestCapacityReservations_BasicOperations(t *testing.T) {
cr := newCapacityReservations()
diskType := types.HardDriveType
// Test initial state
if count := cr.getReservedCount(diskType); count != 0 {
t.Errorf("Expected 0 reserved count initially, got %d", count)
}
// Test add reservation
reservationId := cr.addReservation(diskType, 5)
if reservationId == "" {
t.Error("Expected non-empty reservation ID")
}
if count := cr.getReservedCount(diskType); count != 5 {
t.Errorf("Expected 5 reserved count, got %d", count)
}
// Test multiple reservations
cr.addReservation(diskType, 3)
if count := cr.getReservedCount(diskType); count != 8 {
t.Errorf("Expected 8 reserved count after second reservation, got %d", count)
}
// Test remove reservation
success := cr.removeReservation(reservationId)
if !success {
t.Error("Expected successful removal of existing reservation")
}
if count := cr.getReservedCount(diskType); count != 3 {
t.Errorf("Expected 3 reserved count after removal, got %d", count)
}
// Test remove non-existent reservation
success = cr.removeReservation("non-existent-id")
if success {
t.Error("Expected failure when removing non-existent reservation")
}
}
func TestCapacityReservations_ExpiredCleaning(t *testing.T) {
cr := newCapacityReservations()
diskType := types.HardDriveType
// Add reservations and manipulate their creation time
reservationId1 := cr.addReservation(diskType, 3)
reservationId2 := cr.addReservation(diskType, 2)
// Make one reservation "old"
cr.Lock()
if reservation, exists := cr.reservations[reservationId1]; exists {
reservation.createdAt = time.Now().Add(-10 * time.Minute) // 10 minutes ago
}
cr.Unlock()
// Clean expired reservations (5 minute expiration)
cr.cleanExpiredReservations(5 * time.Minute)
// Only the non-expired reservation should remain
if count := cr.getReservedCount(diskType); count != 2 {
t.Errorf("Expected 2 reserved count after cleaning, got %d", count)
}
// Verify the right reservation was kept
if !cr.removeReservation(reservationId2) {
t.Error("Expected recent reservation to still exist")
}
if cr.removeReservation(reservationId1) {
t.Error("Expected old reservation to be cleaned up")
}
}
func TestCapacityReservations_DifferentDiskTypes(t *testing.T) {
cr := newCapacityReservations()
// Add reservations for different disk types
cr.addReservation(types.HardDriveType, 5)
cr.addReservation(types.SsdType, 3)
// Check counts are separate
if count := cr.getReservedCount(types.HardDriveType); count != 5 {
t.Errorf("Expected 5 HDD reserved count, got %d", count)
}
if count := cr.getReservedCount(types.SsdType); count != 3 {
t.Errorf("Expected 3 SSD reserved count, got %d", count)
}
}
func TestNodeImpl_ReservationMethods(t *testing.T) {
// Create a test data node
dn := NewDataNode("test-node")
diskType := types.HardDriveType
// Set up some capacity
diskUsage := dn.diskUsages.getOrCreateDisk(diskType)
diskUsage.maxVolumeCount = 10
diskUsage.volumeCount = 5 // 5 volumes free initially
option := &VolumeGrowOption{DiskType: diskType}
// Test available space calculation
available := dn.AvailableSpaceFor(option)
if available != 5 {
t.Errorf("Expected 5 available slots, got %d", available)
}
availableForReservation := dn.AvailableSpaceForReservation(option)
if availableForReservation != 5 {
t.Errorf("Expected 5 available slots for reservation, got %d", availableForReservation)
}
// Test successful reservation
reservationId, success := dn.TryReserveCapacity(diskType, 3)
if !success {
t.Error("Expected successful reservation")
}
if reservationId == "" {
t.Error("Expected non-empty reservation ID")
}
// Available space should be reduced by reservations
availableForReservation = dn.AvailableSpaceForReservation(option)
if availableForReservation != 2 {
t.Errorf("Expected 2 available slots after reservation, got %d", availableForReservation)
}
// Base available space should remain unchanged
available = dn.AvailableSpaceFor(option)
if available != 5 {
t.Errorf("Expected base available to remain 5, got %d", available)
}
// Test reservation failure when insufficient capacity
_, success = dn.TryReserveCapacity(diskType, 3)
if success {
t.Error("Expected reservation failure due to insufficient capacity")
}
// Test release reservation
dn.ReleaseReservedCapacity(reservationId)
availableForReservation = dn.AvailableSpaceForReservation(option)
if availableForReservation != 5 {
t.Errorf("Expected 5 available slots after release, got %d", availableForReservation)
}
}
func TestNodeImpl_ConcurrentReservations(t *testing.T) {
dn := NewDataNode("test-node")
diskType := types.HardDriveType
// Set up capacity
diskUsage := dn.diskUsages.getOrCreateDisk(diskType)
diskUsage.maxVolumeCount = 10
diskUsage.volumeCount = 0 // 10 volumes free initially
// Test concurrent reservations using goroutines
var wg sync.WaitGroup
var reservationIds sync.Map
concurrentRequests := 10
wg.Add(concurrentRequests)
for i := 0; i < concurrentRequests; i++ {
go func(i int) {
defer wg.Done()
if reservationId, success := dn.TryReserveCapacity(diskType, 1); success {
reservationIds.Store(reservationId, true)
t.Logf("goroutine %d: Successfully reserved %s", i, reservationId)
} else {
t.Errorf("goroutine %d: Expected successful reservation", i)
}
}(i)
}
wg.Wait()
// Should have no more capacity
option := &VolumeGrowOption{DiskType: diskType}
if available := dn.AvailableSpaceForReservation(option); available != 0 {
t.Errorf("Expected 0 available slots after all reservations, got %d", available)
// Debug: check total reserved
reservedCount := dn.capacityReservations.getReservedCount(diskType)
t.Logf("Debug: Total reserved count: %d", reservedCount)
}
// Next reservation should fail
_, success := dn.TryReserveCapacity(diskType, 1)
if success {
t.Error("Expected reservation failure when at capacity")
}
// Release all reservations
reservationIds.Range(func(key, value interface{}) bool {
dn.ReleaseReservedCapacity(key.(string))
return true
})
// Should have full capacity back
if available := dn.AvailableSpaceForReservation(option); available != 10 {
t.Errorf("Expected 10 available slots after releasing all, got %d", available)
}
}