| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- package sftp
- import (
- "sync"
- )
- type allocator struct {
- sync.Mutex
- available [][]byte
- // map key is the request order
- used map[uint32][][]byte
- }
- func newAllocator() *allocator {
- return &allocator{
- // micro optimization: initialize available pages with an initial capacity
- available: make([][]byte, 0, SftpServerWorkerCount*2),
- used: make(map[uint32][][]byte),
- }
- }
- // GetPage returns a previously allocated and unused []byte or create a new one.
- // The slice have a fixed size = maxMsgLength, this value is suitable for both
- // receiving new packets and reading the files to serve
- func (a *allocator) GetPage(requestOrderID uint32) []byte {
- a.Lock()
- defer a.Unlock()
- var result []byte
- // get an available page and remove it from the available ones.
- if len(a.available) > 0 {
- truncLength := len(a.available) - 1
- result = a.available[truncLength]
- a.available[truncLength] = nil // clear out the internal pointer
- a.available = a.available[:truncLength] // truncate the slice
- }
- // no preallocated slice found, just allocate a new one
- if result == nil {
- result = make([]byte, maxMsgLength)
- }
- // put result in used pages
- a.used[requestOrderID] = append(a.used[requestOrderID], result)
- return result
- }
- // ReleasePages marks unused all pages in use for the given requestID
- func (a *allocator) ReleasePages(requestOrderID uint32) {
- a.Lock()
- defer a.Unlock()
- if used := a.used[requestOrderID]; len(used) > 0 {
- a.available = append(a.available, used...)
- }
- delete(a.used, requestOrderID)
- }
- // Free removes all the used and available pages.
- // Call this method when the allocator is not needed anymore
- func (a *allocator) Free() {
- a.Lock()
- defer a.Unlock()
- a.available = nil
- a.used = make(map[uint32][][]byte)
- }
- func (a *allocator) countUsedPages() int {
- a.Lock()
- defer a.Unlock()
- num := 0
- for _, p := range a.used {
- num += len(p)
- }
- return num
- }
- func (a *allocator) countAvailablePages() int {
- a.Lock()
- defer a.Unlock()
- return len(a.available)
- }
- func (a *allocator) isRequestOrderIDUsed(requestOrderID uint32) bool {
- a.Lock()
- defer a.Unlock()
- _, ok := a.used[requestOrderID]
- return ok
- }
|