mirror of https://github.com/pkg/sftp.git
136 lines
5.5 KiB
Go
136 lines
5.5 KiB
Go
package sftp
|
|
|
|
import (
|
|
"strconv"
|
|
"sync/atomic"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestAllocator(t *testing.T) {
|
|
allocator := newAllocator()
|
|
// get a page for request order id 1
|
|
page := allocator.GetPage(1)
|
|
page[1] = uint8(1)
|
|
assert.Equal(t, maxMsgLength, len(page))
|
|
assert.Equal(t, 1, allocator.countUsedPages())
|
|
// get another page for request order id 1, we now have 2 used pages
|
|
page = allocator.GetPage(1)
|
|
page[0] = uint8(2)
|
|
assert.Equal(t, 2, allocator.countUsedPages())
|
|
// get another page for request order id 1, we now have 3 used pages
|
|
page = allocator.GetPage(1)
|
|
page[2] = uint8(3)
|
|
assert.Equal(t, 3, allocator.countUsedPages())
|
|
// release the page for request order id 1, we now have 3 available pages
|
|
allocator.ReleasePages(1)
|
|
assert.NotContains(t, allocator.used, 1)
|
|
assert.Equal(t, 3, allocator.countAvailablePages())
|
|
// get a page for request order id 2
|
|
// we get the latest released page, let's verify that by checking the previously written values
|
|
// so we are sure we are reusing a previously allocated page
|
|
page = allocator.GetPage(2)
|
|
assert.Equal(t, uint8(3), page[2])
|
|
assert.Equal(t, 2, allocator.countAvailablePages())
|
|
assert.Equal(t, 1, allocator.countUsedPages())
|
|
page = allocator.GetPage(2)
|
|
assert.Equal(t, uint8(2), page[0])
|
|
assert.Equal(t, 1, allocator.countAvailablePages())
|
|
assert.Equal(t, 2, allocator.countUsedPages())
|
|
page = allocator.GetPage(2)
|
|
assert.Equal(t, uint8(1), page[1])
|
|
// we now have 3 used pages for request order id 2 and no available pages
|
|
assert.Equal(t, 0, allocator.countAvailablePages())
|
|
assert.Equal(t, 3, allocator.countUsedPages())
|
|
assert.True(t, allocator.isRequestOrderIDUsed(2), "page with request order id 2 must be used")
|
|
assert.False(t, allocator.isRequestOrderIDUsed(1), "page with request order id 1 must be not used")
|
|
// release some request order id with no allocated pages, should have no effect
|
|
allocator.ReleasePages(1)
|
|
allocator.ReleasePages(3)
|
|
assert.Equal(t, 0, allocator.countAvailablePages())
|
|
assert.Equal(t, 3, allocator.countUsedPages())
|
|
assert.True(t, allocator.isRequestOrderIDUsed(2), "page with request order id 2 must be used")
|
|
assert.False(t, allocator.isRequestOrderIDUsed(1), "page with request order id 1 must be not used")
|
|
// now get some pages for another request order id
|
|
allocator.GetPage(3)
|
|
// we now must have 3 used pages for request order id 2 and 1 used page for request order id 3
|
|
assert.Equal(t, 0, allocator.countAvailablePages())
|
|
assert.Equal(t, 4, allocator.countUsedPages())
|
|
assert.True(t, allocator.isRequestOrderIDUsed(2), "page with request order id 2 must be used")
|
|
assert.True(t, allocator.isRequestOrderIDUsed(3), "page with request order id 3 must be used")
|
|
assert.False(t, allocator.isRequestOrderIDUsed(1), "page with request order id 1 must be not used")
|
|
// get another page for request order id 3
|
|
allocator.GetPage(3)
|
|
assert.Equal(t, 0, allocator.countAvailablePages())
|
|
assert.Equal(t, 5, allocator.countUsedPages())
|
|
assert.True(t, allocator.isRequestOrderIDUsed(2), "page with request order id 2 must be used")
|
|
assert.True(t, allocator.isRequestOrderIDUsed(3), "page with request order id 3 must be used")
|
|
assert.False(t, allocator.isRequestOrderIDUsed(1), "page with request order id 1 must be not used")
|
|
// now release the pages for request order id 3
|
|
allocator.ReleasePages(3)
|
|
assert.Equal(t, 2, allocator.countAvailablePages())
|
|
assert.Equal(t, 3, allocator.countUsedPages())
|
|
assert.True(t, allocator.isRequestOrderIDUsed(2), "page with request order id 2 must be used")
|
|
assert.False(t, allocator.isRequestOrderIDUsed(1), "page with request order id 1 must be not used")
|
|
assert.False(t, allocator.isRequestOrderIDUsed(3), "page with request order id 3 must be not used")
|
|
// again check we are reusing previously allocated pages.
|
|
// We have written nothing to the 2 last requested page so release them and get the third one
|
|
allocator.ReleasePages(2)
|
|
assert.Equal(t, 5, allocator.countAvailablePages())
|
|
assert.Equal(t, 0, allocator.countUsedPages())
|
|
assert.False(t, allocator.isRequestOrderIDUsed(2), "page with request order id 2 must be not used")
|
|
allocator.GetPage(4)
|
|
allocator.GetPage(4)
|
|
page = allocator.GetPage(4)
|
|
assert.Equal(t, uint8(3), page[2])
|
|
assert.Equal(t, 2, allocator.countAvailablePages())
|
|
assert.Equal(t, 3, allocator.countUsedPages())
|
|
assert.True(t, allocator.isRequestOrderIDUsed(4), "page with request order id 4 must be used")
|
|
// free the allocator
|
|
allocator.Free()
|
|
assert.Equal(t, 0, allocator.countAvailablePages())
|
|
assert.Equal(t, 0, allocator.countUsedPages())
|
|
}
|
|
|
|
func BenchmarkAllocatorSerial(b *testing.B) {
|
|
allocator := newAllocator()
|
|
for i := 0; i < b.N; i++ {
|
|
benchAllocator(allocator, uint32(i))
|
|
}
|
|
}
|
|
|
|
func BenchmarkAllocatorParallel(b *testing.B) {
|
|
var counter uint32
|
|
allocator := newAllocator()
|
|
for i := 1; i <= 8; i *= 2 {
|
|
b.Run(strconv.Itoa(i), func(b *testing.B) {
|
|
b.SetParallelism(i)
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
benchAllocator(allocator, atomic.AddUint32(&counter, 1))
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
func benchAllocator(allocator *allocator, requestOrderID uint32) {
|
|
// simulates the page requested in recvPacket
|
|
allocator.GetPage(requestOrderID)
|
|
// simulates the page requested in fileget for downloads
|
|
allocator.GetPage(requestOrderID)
|
|
// release the allocated pages
|
|
allocator.ReleasePages(requestOrderID)
|
|
}
|
|
|
|
// useful for debug
|
|
func printAllocatorContents(allocator *allocator) {
|
|
for o, u := range allocator.used {
|
|
debug("used order id: %v, values: %+v", o, u)
|
|
}
|
|
for _, v := range allocator.available {
|
|
debug("available, values: %+v", v)
|
|
}
|
|
}
|