You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

159 lines
3.0 KiB

  1. package client
  2. import (
  3. "errors"
  4. "math/rand"
  5. "sync"
  6. )
  7. const (
  8. poolSize = 10
  9. )
  10. var (
  11. ErrNotFound = errors.New("Server Not Found")
  12. SelectWithRate = selectWithRate
  13. SelectRandom = selectRandom
  14. )
  15. type poolClient struct {
  16. *Client
  17. Rate int
  18. }
  19. type SelectionHandler func(map[string]*poolClient, string) string
  20. func selectWithRate(pool map[string]*poolClient,
  21. last string) (addr string) {
  22. total := 0
  23. for _, item := range pool {
  24. total += item.Rate
  25. if rand.Intn(total) < item.Rate {
  26. return item.addr
  27. }
  28. }
  29. return last
  30. }
  31. func selectRandom(pool map[string]*poolClient,
  32. last string) (addr string) {
  33. r := rand.Intn(len(pool))
  34. i := 0
  35. for k, _ := range pool {
  36. if r == i {
  37. return k
  38. }
  39. i++
  40. }
  41. return last
  42. }
  43. type Pool struct {
  44. SelectionHandler SelectionHandler
  45. ErrorHandler ErrorHandler
  46. clients map[string]*poolClient
  47. last string
  48. mutex sync.Mutex
  49. }
  50. // Return a new pool.
  51. func NewPool() (pool *Pool) {
  52. return &Pool{
  53. clients: make(map[string]*poolClient, poolSize),
  54. SelectionHandler: SelectWithRate,
  55. }
  56. }
  57. // Add a server with rate.
  58. func (pool *Pool) Add(net, addr string, rate int) (err error) {
  59. pool.mutex.Lock()
  60. defer pool.mutex.Unlock()
  61. var item *poolClient
  62. var ok bool
  63. if item, ok = pool.clients[addr]; ok {
  64. item.Rate = rate
  65. } else {
  66. var client *Client
  67. client, err = New(net, addr)
  68. if err == nil {
  69. item = &poolClient{Client: client, Rate: rate}
  70. pool.clients[addr] = item
  71. }
  72. }
  73. return
  74. }
  75. // Remove a server.
  76. func (pool *Pool) Remove(addr string) {
  77. pool.mutex.Lock()
  78. defer pool.mutex.Unlock()
  79. delete(pool.clients, addr)
  80. }
  81. func (pool *Pool) Do(funcname string, data []byte,
  82. flag byte, h ResponseHandler) (addr, handle string, err error) {
  83. client := pool.selectServer()
  84. handle, err = client.Do(funcname, data, flag, h)
  85. addr = client.addr
  86. return
  87. }
  88. func (pool *Pool) DoBg(funcname string, data []byte,
  89. flag byte) (addr, handle string, err error) {
  90. client := pool.selectServer()
  91. handle, err = client.DoBg(funcname, data, flag)
  92. addr = client.addr
  93. return
  94. }
  95. // Get job status from job server.
  96. // !!!Not fully tested.!!!
  97. func (pool *Pool) Status(addr, handle string) (status *Status, err error) {
  98. if client, ok := pool.clients[addr]; ok {
  99. status, err = client.Status(handle)
  100. } else {
  101. err = ErrNotFound
  102. }
  103. return
  104. }
  105. // Send a something out, get the samething back.
  106. func (pool *Pool) Echo(addr string, data []byte) (echo []byte, err error) {
  107. var client *poolClient
  108. if addr == "" {
  109. client = pool.selectServer()
  110. } else {
  111. var ok bool
  112. if client, ok = pool.clients[addr]; !ok {
  113. err = ErrNotFound
  114. return
  115. }
  116. }
  117. echo, err = client.Echo(data)
  118. return
  119. }
  120. // Close
  121. func (pool *Pool) Close() (err map[string]error) {
  122. err = make(map[string]error)
  123. for _, c := range pool.clients {
  124. err[c.addr] = c.Close()
  125. }
  126. return
  127. }
  128. // selecting server
  129. func (pool *Pool) selectServer() (client *poolClient) {
  130. for client == nil {
  131. addr := pool.SelectionHandler(pool.clients, pool.last)
  132. var ok bool
  133. if client, ok = pool.clients[addr]; ok {
  134. pool.last = addr
  135. break
  136. }
  137. }
  138. return
  139. }