github.com/pkg/sftp@v1.13.6/allocator_test.go (about) 1 package sftp 2 3 import ( 4 "strconv" 5 "sync/atomic" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 ) 10 11 func TestAllocator(t *testing.T) { 12 allocator := newAllocator() 13 // get a page for request order id 1 14 page := allocator.GetPage(1) 15 page[1] = uint8(1) 16 assert.Equal(t, maxMsgLength, len(page)) 17 assert.Equal(t, 1, allocator.countUsedPages()) 18 // get another page for request order id 1, we now have 2 used pages 19 page = allocator.GetPage(1) 20 page[0] = uint8(2) 21 assert.Equal(t, 2, allocator.countUsedPages()) 22 // get another page for request order id 1, we now have 3 used pages 23 page = allocator.GetPage(1) 24 page[2] = uint8(3) 25 assert.Equal(t, 3, allocator.countUsedPages()) 26 // release the page for request order id 1, we now have 3 available pages 27 allocator.ReleasePages(1) 28 assert.NotContains(t, allocator.used, 1) 29 assert.Equal(t, 3, allocator.countAvailablePages()) 30 // get a page for request order id 2 31 // we get the latest released page, let's verify that by checking the previously written values 32 // so we are sure we are reusing a previously allocated page 33 page = allocator.GetPage(2) 34 assert.Equal(t, uint8(3), page[2]) 35 assert.Equal(t, 2, allocator.countAvailablePages()) 36 assert.Equal(t, 1, allocator.countUsedPages()) 37 page = allocator.GetPage(2) 38 assert.Equal(t, uint8(2), page[0]) 39 assert.Equal(t, 1, allocator.countAvailablePages()) 40 assert.Equal(t, 2, allocator.countUsedPages()) 41 page = allocator.GetPage(2) 42 assert.Equal(t, uint8(1), page[1]) 43 // we now have 3 used pages for request order id 2 and no available pages 44 assert.Equal(t, 0, allocator.countAvailablePages()) 45 assert.Equal(t, 3, allocator.countUsedPages()) 46 assert.True(t, allocator.isRequestOrderIDUsed(2), "page with request order id 2 must be used") 47 assert.False(t, allocator.isRequestOrderIDUsed(1), "page with request order id 1 must be not used") 48 // release some request order id with no allocated pages, should have no effect 49 allocator.ReleasePages(1) 50 allocator.ReleasePages(3) 51 assert.Equal(t, 0, allocator.countAvailablePages()) 52 assert.Equal(t, 3, allocator.countUsedPages()) 53 assert.True(t, allocator.isRequestOrderIDUsed(2), "page with request order id 2 must be used") 54 assert.False(t, allocator.isRequestOrderIDUsed(1), "page with request order id 1 must be not used") 55 // now get some pages for another request order id 56 allocator.GetPage(3) 57 // we now must have 3 used pages for request order id 2 and 1 used page for request order id 3 58 assert.Equal(t, 0, allocator.countAvailablePages()) 59 assert.Equal(t, 4, allocator.countUsedPages()) 60 assert.True(t, allocator.isRequestOrderIDUsed(2), "page with request order id 2 must be used") 61 assert.True(t, allocator.isRequestOrderIDUsed(3), "page with request order id 3 must be used") 62 assert.False(t, allocator.isRequestOrderIDUsed(1), "page with request order id 1 must be not used") 63 // get another page for request order id 3 64 allocator.GetPage(3) 65 assert.Equal(t, 0, allocator.countAvailablePages()) 66 assert.Equal(t, 5, allocator.countUsedPages()) 67 assert.True(t, allocator.isRequestOrderIDUsed(2), "page with request order id 2 must be used") 68 assert.True(t, allocator.isRequestOrderIDUsed(3), "page with request order id 3 must be used") 69 assert.False(t, allocator.isRequestOrderIDUsed(1), "page with request order id 1 must be not used") 70 // now release the pages for request order id 3 71 allocator.ReleasePages(3) 72 assert.Equal(t, 2, allocator.countAvailablePages()) 73 assert.Equal(t, 3, allocator.countUsedPages()) 74 assert.True(t, allocator.isRequestOrderIDUsed(2), "page with request order id 2 must be used") 75 assert.False(t, allocator.isRequestOrderIDUsed(1), "page with request order id 1 must be not used") 76 assert.False(t, allocator.isRequestOrderIDUsed(3), "page with request order id 3 must be not used") 77 // again check we are reusing previously allocated pages. 78 // We have written nothing to the 2 last requested page so release them and get the third one 79 allocator.ReleasePages(2) 80 assert.Equal(t, 5, allocator.countAvailablePages()) 81 assert.Equal(t, 0, allocator.countUsedPages()) 82 assert.False(t, allocator.isRequestOrderIDUsed(2), "page with request order id 2 must be not used") 83 allocator.GetPage(4) 84 allocator.GetPage(4) 85 page = allocator.GetPage(4) 86 assert.Equal(t, uint8(3), page[2]) 87 assert.Equal(t, 2, allocator.countAvailablePages()) 88 assert.Equal(t, 3, allocator.countUsedPages()) 89 assert.True(t, allocator.isRequestOrderIDUsed(4), "page with request order id 4 must be used") 90 // free the allocator 91 allocator.Free() 92 assert.Equal(t, 0, allocator.countAvailablePages()) 93 assert.Equal(t, 0, allocator.countUsedPages()) 94 } 95 96 func BenchmarkAllocatorSerial(b *testing.B) { 97 allocator := newAllocator() 98 for i := 0; i < b.N; i++ { 99 benchAllocator(allocator, uint32(i)) 100 } 101 } 102 103 func BenchmarkAllocatorParallel(b *testing.B) { 104 var counter uint32 105 allocator := newAllocator() 106 for i := 1; i <= 8; i *= 2 { 107 b.Run(strconv.Itoa(i), func(b *testing.B) { 108 b.SetParallelism(i) 109 b.RunParallel(func(pb *testing.PB) { 110 for pb.Next() { 111 benchAllocator(allocator, atomic.AddUint32(&counter, 1)) 112 } 113 }) 114 }) 115 } 116 } 117 118 func benchAllocator(allocator *allocator, requestOrderID uint32) { 119 // simulates the page requested in recvPacket 120 allocator.GetPage(requestOrderID) 121 // simulates the page requested in fileget for downloads 122 allocator.GetPage(requestOrderID) 123 // release the allocated pages 124 allocator.ReleasePages(requestOrderID) 125 } 126 127 // useful for debug 128 func printAllocatorContents(allocator *allocator) { 129 for o, u := range allocator.used { 130 debug("used order id: %v, values: %+v", o, u) 131 } 132 for _, v := range allocator.available { 133 debug("available, values: %+v", v) 134 } 135 }