kv.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. package storage
  2. import (
  3. "bufio"
  4. "fmt"
  5. "net"
  6. "strings"
  7. "sync"
  8. "time"
  9. )
  10. // KVClient represents a connection to PizzaKV.
  11. type KVClient struct {
  12. conn net.Conn
  13. reader *bufio.Reader
  14. writer *bufio.Writer
  15. mu sync.Mutex
  16. }
  17. // NewKVClient creates a new KV client connected to the given address.
  18. func NewKVClient(addr string) (*KVClient, error) {
  19. conn, err := net.Dial("tcp", addr)
  20. if err != nil {
  21. return nil, fmt.Errorf("failed to connect to PizzaKV: %w", err)
  22. }
  23. return &KVClient{
  24. conn: conn,
  25. reader: bufio.NewReader(conn),
  26. writer: bufio.NewWriter(conn),
  27. }, nil
  28. }
  29. // Close closes the connection.
  30. func (c *KVClient) Close() error {
  31. c.mu.Lock()
  32. defer c.mu.Unlock()
  33. if c.conn != nil {
  34. return c.conn.Close()
  35. }
  36. return nil
  37. }
  38. // SetDeadline sets the read/write deadline.
  39. func (c *KVClient) SetDeadline(t time.Time) error {
  40. return c.conn.SetDeadline(t)
  41. }
  42. // Write stores a key-value pair.
  43. func (c *KVClient) Write(key, value string) error {
  44. c.mu.Lock()
  45. defer c.mu.Unlock()
  46. cmd := fmt.Sprintf("write %s|%s\r", key, value)
  47. if _, err := c.writer.WriteString(cmd); err != nil {
  48. return fmt.Errorf("write command failed: %w", err)
  49. }
  50. if err := c.writer.Flush(); err != nil {
  51. return fmt.Errorf("flush failed: %w", err)
  52. }
  53. resp, err := c.reader.ReadString('\r')
  54. if err != nil {
  55. return fmt.Errorf("read response failed: %w", err)
  56. }
  57. resp = strings.TrimSuffix(resp, "\r")
  58. if resp != "success" {
  59. return fmt.Errorf("write failed: %s", resp)
  60. }
  61. return nil
  62. }
  63. // Read retrieves a value by key.
  64. func (c *KVClient) Read(key string) (string, error) {
  65. c.mu.Lock()
  66. defer c.mu.Unlock()
  67. cmd := fmt.Sprintf("read %s\r", key)
  68. if _, err := c.writer.WriteString(cmd); err != nil {
  69. return "", fmt.Errorf("read command failed: %w", err)
  70. }
  71. if err := c.writer.Flush(); err != nil {
  72. return "", fmt.Errorf("flush failed: %w", err)
  73. }
  74. resp, err := c.reader.ReadString('\r')
  75. if err != nil {
  76. return "", fmt.Errorf("read response failed: %w", err)
  77. }
  78. resp = strings.TrimSuffix(resp, "\r")
  79. if resp == "error" {
  80. return "", ErrKeyNotFound
  81. }
  82. return resp, nil
  83. }
  84. // Delete removes a key.
  85. func (c *KVClient) Delete(key string) error {
  86. c.mu.Lock()
  87. defer c.mu.Unlock()
  88. cmd := fmt.Sprintf("delete %s\r", key)
  89. if _, err := c.writer.WriteString(cmd); err != nil {
  90. return fmt.Errorf("delete command failed: %w", err)
  91. }
  92. if err := c.writer.Flush(); err != nil {
  93. return fmt.Errorf("flush failed: %w", err)
  94. }
  95. resp, err := c.reader.ReadString('\r')
  96. if err != nil {
  97. return fmt.Errorf("read response failed: %w", err)
  98. }
  99. resp = strings.TrimSuffix(resp, "\r")
  100. if resp != "success" && resp != "error" {
  101. return fmt.Errorf("delete failed: %s", resp)
  102. }
  103. return nil
  104. }
  105. // Reads retrieves all values with a key prefix.
  106. func (c *KVClient) Reads(prefix string) ([]string, error) {
  107. c.mu.Lock()
  108. defer c.mu.Unlock()
  109. cmd := fmt.Sprintf("reads %s\r", prefix)
  110. if _, err := c.writer.WriteString(cmd); err != nil {
  111. return nil, fmt.Errorf("reads command failed: %w", err)
  112. }
  113. if err := c.writer.Flush(); err != nil {
  114. return nil, fmt.Errorf("flush failed: %w", err)
  115. }
  116. resp, err := c.reader.ReadString('\r')
  117. if err != nil {
  118. return nil, fmt.Errorf("read response failed: %w", err)
  119. }
  120. resp = strings.TrimSuffix(resp, "\r")
  121. if resp == "" {
  122. return nil, nil
  123. }
  124. values := strings.Split(resp, "\n")
  125. result := make([]string, 0, len(values))
  126. for _, v := range values {
  127. if v != "" {
  128. result = append(result, v)
  129. }
  130. }
  131. return result, nil
  132. }
  133. // IsAlive checks if the connection is still alive.
  134. func (c *KVClient) IsAlive() bool {
  135. c.mu.Lock()
  136. defer c.mu.Unlock()
  137. if c.conn == nil {
  138. return false
  139. }
  140. // Try to set a short deadline and do a no-op check
  141. c.conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
  142. defer c.conn.SetReadDeadline(time.Time{})
  143. one := make([]byte, 1)
  144. c.conn.SetReadDeadline(time.Now().Add(1 * time.Millisecond))
  145. _, err := c.conn.Read(one)
  146. if err != nil {
  147. if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
  148. return true // Timeout is expected
  149. }
  150. return false
  151. }
  152. return true
  153. }
  154. // ErrKeyNotFound is returned when a key doesn't exist.
  155. var ErrKeyNotFound = fmt.Errorf("key not found")
  156. // KVPool manages a pool of KV client connections.
  157. type KVPool struct {
  158. addr string
  159. pool chan *KVClient
  160. size int
  161. timeout time.Duration
  162. mu sync.Mutex
  163. closed bool
  164. }
  165. // NewKVPool creates a new connection pool.
  166. func NewKVPool(addr string, size int, timeout time.Duration) (*KVPool, error) {
  167. p := &KVPool{
  168. addr: addr,
  169. pool: make(chan *KVClient, size),
  170. size: size,
  171. timeout: timeout,
  172. }
  173. // Pre-create connections
  174. for i := 0; i < size; i++ {
  175. client, err := NewKVClient(addr)
  176. if err != nil {
  177. // Close any created connections
  178. p.Close()
  179. return nil, fmt.Errorf("failed to create connection pool: %w", err)
  180. }
  181. p.pool <- client
  182. }
  183. return p, nil
  184. }
  185. // Get retrieves a connection from the pool.
  186. func (p *KVPool) Get() (*KVClient, error) {
  187. p.mu.Lock()
  188. if p.closed {
  189. p.mu.Unlock()
  190. return nil, fmt.Errorf("pool is closed")
  191. }
  192. p.mu.Unlock()
  193. select {
  194. case client := <-p.pool:
  195. // Validate connection
  196. if client != nil && client.conn != nil {
  197. if p.timeout > 0 {
  198. client.SetDeadline(time.Now().Add(p.timeout))
  199. }
  200. return client, nil
  201. }
  202. // Stale connection — replace with a fresh one
  203. return NewKVClient(p.addr)
  204. case <-time.After(30 * time.Second):
  205. return nil, fmt.Errorf("kv pool timeout: no connection available after 30s")
  206. }
  207. }
  208. // Put returns a connection to the pool.
  209. func (p *KVPool) Put(client *KVClient) {
  210. if client == nil {
  211. return
  212. }
  213. p.mu.Lock()
  214. if p.closed {
  215. p.mu.Unlock()
  216. client.Close()
  217. return
  218. }
  219. p.mu.Unlock()
  220. // Clear deadline
  221. client.SetDeadline(time.Time{})
  222. select {
  223. case p.pool <- client:
  224. // Returned to pool
  225. default:
  226. // Pool full, close connection
  227. client.Close()
  228. }
  229. }
  230. // Close closes all connections in the pool.
  231. func (p *KVPool) Close() error {
  232. p.mu.Lock()
  233. if p.closed {
  234. p.mu.Unlock()
  235. return nil
  236. }
  237. p.closed = true
  238. p.mu.Unlock()
  239. close(p.pool)
  240. for client := range p.pool {
  241. if client != nil {
  242. client.Close()
  243. }
  244. }
  245. return nil
  246. }
  247. // WithClient executes a function with a pooled connection.
  248. func (p *KVPool) WithClient(fn func(*KVClient) error) error {
  249. client, err := p.Get()
  250. if err != nil {
  251. return err
  252. }
  253. defer p.Put(client)
  254. return fn(client)
  255. }