allocator.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package sftp
  2. import (
  3. "sync"
  4. )
  5. type allocator struct {
  6. sync.Mutex
  7. available [][]byte
  8. // map key is the request order
  9. used map[uint32][][]byte
  10. }
  11. func newAllocator() *allocator {
  12. return &allocator{
  13. // micro optimization: initialize available pages with an initial capacity
  14. available: make([][]byte, 0, SftpServerWorkerCount*2),
  15. used: make(map[uint32][][]byte),
  16. }
  17. }
  18. // GetPage returns a previously allocated and unused []byte or create a new one.
  19. // The slice have a fixed size = maxMsgLength, this value is suitable for both
  20. // receiving new packets and reading the files to serve
  21. func (a *allocator) GetPage(requestOrderID uint32) []byte {
  22. a.Lock()
  23. defer a.Unlock()
  24. var result []byte
  25. // get an available page and remove it from the available ones.
  26. if len(a.available) > 0 {
  27. truncLength := len(a.available) - 1
  28. result = a.available[truncLength]
  29. a.available[truncLength] = nil // clear out the internal pointer
  30. a.available = a.available[:truncLength] // truncate the slice
  31. }
  32. // no preallocated slice found, just allocate a new one
  33. if result == nil {
  34. result = make([]byte, maxMsgLength)
  35. }
  36. // put result in used pages
  37. a.used[requestOrderID] = append(a.used[requestOrderID], result)
  38. return result
  39. }
  40. // ReleasePages marks unused all pages in use for the given requestID
  41. func (a *allocator) ReleasePages(requestOrderID uint32) {
  42. a.Lock()
  43. defer a.Unlock()
  44. if used := a.used[requestOrderID]; len(used) > 0 {
  45. a.available = append(a.available, used...)
  46. }
  47. delete(a.used, requestOrderID)
  48. }
  49. // Free removes all the used and available pages.
  50. // Call this method when the allocator is not needed anymore
  51. func (a *allocator) Free() {
  52. a.Lock()
  53. defer a.Unlock()
  54. a.available = nil
  55. a.used = make(map[uint32][][]byte)
  56. }
  57. func (a *allocator) countUsedPages() int {
  58. a.Lock()
  59. defer a.Unlock()
  60. num := 0
  61. for _, p := range a.used {
  62. num += len(p)
  63. }
  64. return num
  65. }
  66. func (a *allocator) countAvailablePages() int {
  67. a.Lock()
  68. defer a.Unlock()
  69. return len(a.available)
  70. }
  71. func (a *allocator) isRequestOrderIDUsed(requestOrderID uint32) bool {
  72. a.Lock()
  73. defer a.Unlock()
  74. _, ok := a.used[requestOrderID]
  75. return ok
  76. }