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.
 
 
 

204 lines
5.4 KiB

  1. // Copyright 2011 Xing Xing <mikespook@gmail.com> All rights reserved.
  2. // Use of this source code is governed by a MIT
  3. // license that can be found in the LICENSE file.
  4. package worker
  5. import (
  6. "io"
  7. "net"
  8. "github.com/mikespook/gearman-go/common"
  9. )
  10. // The agent of job server.
  11. type agent struct {
  12. conn net.Conn
  13. worker *Worker
  14. in chan []byte
  15. out chan *Job
  16. addr string
  17. }
  18. // Create the agent of job server.
  19. func newAgent(addr string, worker *Worker) (a *agent, err error) {
  20. conn, err := net.Dial(common.NETWORK, addr)
  21. if err != nil {
  22. return
  23. }
  24. a = &agent{
  25. conn: conn,
  26. worker: worker,
  27. addr: addr,
  28. in: make(chan []byte, common.QUEUE_SIZE),
  29. out: make(chan *Job, common.QUEUE_SIZE),
  30. }
  31. // reset abilities
  32. a.WriteJob(newJob(common.REQ, common.RESET_ABILITIES, nil))
  33. return
  34. }
  35. // outputing loop
  36. func (a *agent) outLoop() {
  37. ok := true
  38. var job *Job
  39. for a.worker.running && ok {
  40. if job, ok = <-a.out; ok {
  41. if err := a.write(job.Encode()); err != nil {
  42. a.worker.err(err)
  43. }
  44. }
  45. }
  46. }
  47. // inputing loop
  48. func (a *agent) inLoop() {
  49. defer func() {
  50. if r := recover(); r != nil {
  51. a.worker.err(common.Errorf("Exiting: %s", r))
  52. }
  53. close(a.in)
  54. close(a.out)
  55. a.worker.removeAgent(a)
  56. }()
  57. for a.worker.running {
  58. a.WriteJob(newJob(common.REQ, common.PRE_SLEEP, nil))
  59. RESTART:
  60. // got noop msg and in queue is zero, grab job
  61. rel, err := a.read()
  62. if err != nil {
  63. if err == common.ErrConnection {
  64. for i := 0; i < 3 && a.worker.running; i++ {
  65. if conn, err := net.Dial(common.NETWORK, a.addr); err != nil {
  66. a.worker.err(common.Errorf("Reconnection: %d faild", i))
  67. continue
  68. } else {
  69. a.conn = conn
  70. goto RESTART
  71. }
  72. }
  73. a.worker.err(err)
  74. break
  75. }
  76. a.worker.err(err)
  77. continue
  78. }
  79. job, err := decodeJob(rel)
  80. if err != nil {
  81. a.worker.err(err)
  82. continue
  83. }
  84. switch job.DataType {
  85. case common.NOOP:
  86. a.WriteJob(newJob(common.REQ, common.GRAB_JOB_UNIQ, nil))
  87. case common.ERROR, common.ECHO_RES, common.JOB_ASSIGN_UNIQ, common.JOB_ASSIGN:
  88. if a.worker.running {
  89. if a.worker.limit != nil {
  90. a.worker.limit <- true
  91. }
  92. job.agent = a
  93. a.worker.in <- job
  94. }
  95. }
  96. }
  97. }
  98. func (a *agent) Close() {
  99. a.conn.Close()
  100. }
  101. func (a *agent) Work() {
  102. go a.outLoop()
  103. go a.inLoop()
  104. }
  105. func (a *agent) readData(length int) (data []byte, err error) {
  106. n := 0
  107. buf := make([]byte, common.BUFFER_SIZE)
  108. // read until data can be unpacked
  109. for i := length; i > 0 || len(data) < common.PACKET_LEN; i -= n {
  110. if n, err = a.conn.Read(buf); err != nil {
  111. if err == io.EOF && n == 0 {
  112. if data == nil {
  113. err = common.ErrConnection
  114. return
  115. }
  116. return data, nil
  117. }
  118. return
  119. }
  120. data = append(data, buf[0:n]...)
  121. if n < common.BUFFER_SIZE {
  122. break
  123. }
  124. }
  125. return
  126. }
  127. func (a *agent) unpack(data []byte) ([]byte, int, bool) {
  128. tl := len(data)
  129. start := 0
  130. for i := 0; i < tl+1-common.PACKET_LEN; i++ {
  131. if start+common.PACKET_LEN > tl { // too few data to unpack, read more
  132. return nil, common.PACKET_LEN, false
  133. }
  134. if string(data[start:start+4]) == common.RES_STR {
  135. l := int(common.BytesToUint32([4]byte{data[start+8],
  136. data[start+9], data[start+10], data[start+11]}))
  137. total := l + common.PACKET_LEN
  138. if total == tl { // data is what we want
  139. return data, common.PACKET_LEN, true
  140. } else if total < tl { // data[:total] is what we want, data[total:] is the more
  141. a.in <- data[total:]
  142. data = data[start:total]
  143. return data, common.PACKET_LEN, true
  144. } else { // ops! It won't be possible.
  145. return nil, total - tl, false
  146. }
  147. } else { // flag was not found, move to next step
  148. start++
  149. }
  150. }
  151. return nil, common.PACKET_LEN, false
  152. }
  153. func (a *agent) read() (rel []byte, err error) {
  154. var data []byte
  155. ok := false
  156. l := common.PACKET_LEN
  157. for !ok {
  158. inlen := len(a.in)
  159. if inlen > 0 {
  160. // in queue is not empty
  161. for i := 0; i < inlen; i++ {
  162. data = append(data, <-a.in...)
  163. }
  164. } else {
  165. var d []byte
  166. d, err = a.readData(l)
  167. if err != nil {
  168. return
  169. }
  170. data = append(data, d...)
  171. }
  172. rel, l, ok = a.unpack(data)
  173. }
  174. return
  175. }
  176. // Send a job to the job server.
  177. func (a *agent) WriteJob(job *Job) {
  178. a.out <- job
  179. }
  180. // Internal write the encoded job.
  181. func (a *agent) write(buf []byte) (err error) {
  182. var n int
  183. for i := 0; i < len(buf); i += n {
  184. n, err = a.conn.Write(buf[i:])
  185. if err != nil {
  186. return err
  187. }
  188. }
  189. return
  190. }