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)
 | |
| 	}
 | |
| }
 |