kv.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  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. // Filter out empty strings
  126. result := make([]string, 0, len(values))
  127. for _, v := range values {
  128. if v != "" {
  129. result = append(result, v)
  130. }
  131. }
  132. return result, nil
  133. }
  134. // IsAlive checks if the connection is still alive.
  135. func (c *KVClient) IsAlive() bool {
  136. c.mu.Lock()
  137. defer c.mu.Unlock()
  138. if c.conn == nil {
  139. return false
  140. }
  141. // Try to set a short deadline and do a no-op check
  142. c.conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
  143. defer c.conn.SetReadDeadline(time.Time{})
  144. one := make([]byte, 1)
  145. c.conn.SetReadDeadline(time.Now().Add(1 * time.Millisecond))
  146. _, err := c.conn.Read(one)
  147. if err != nil {
  148. if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
  149. return true // Timeout is expected
  150. }
  151. return false
  152. }
  153. return true
  154. }
  155. // ErrKeyNotFound is returned when a key doesn't exist.
  156. var ErrKeyNotFound = fmt.Errorf("key not found")
  157. // KVPool manages a pool of KV client connections.
  158. type KVPool struct {
  159. addr string
  160. pool chan *KVClient
  161. size int
  162. timeout time.Duration
  163. mu sync.Mutex
  164. closed bool
  165. }
  166. // NewKVPool creates a new connection pool.
  167. func NewKVPool(addr string, size int, timeout time.Duration) (*KVPool, error) {
  168. p := &KVPool{
  169. addr: addr,
  170. pool: make(chan *KVClient, size),
  171. size: size,
  172. timeout: timeout,
  173. }
  174. // Pre-create connections
  175. for i := 0; i < size; i++ {
  176. client, err := NewKVClient(addr)
  177. if err != nil {
  178. // Close any created connections
  179. p.Close()
  180. return nil, fmt.Errorf("failed to create connection pool: %w", err)
  181. }
  182. p.pool <- client
  183. }
  184. return p, nil
  185. }
  186. // Get retrieves a connection from the pool.
  187. func (p *KVPool) Get() (*KVClient, error) {
  188. p.mu.Lock()
  189. if p.closed {
  190. p.mu.Unlock()
  191. return nil, fmt.Errorf("pool is closed")
  192. }
  193. p.mu.Unlock()
  194. select {
  195. case client := <-p.pool:
  196. // Validate connection
  197. if client != nil && client.conn != nil {
  198. if p.timeout > 0 {
  199. client.SetDeadline(time.Now().Add(p.timeout))
  200. }
  201. return client, nil
  202. }
  203. // Create new connection if stale
  204. return NewKVClient(p.addr)
  205. default:
  206. // Pool empty, create new connection
  207. return NewKVClient(p.addr)
  208. }
  209. }
  210. // Put returns a connection to the pool.
  211. func (p *KVPool) Put(client *KVClient) {
  212. if client == nil {
  213. return
  214. }
  215. p.mu.Lock()
  216. if p.closed {
  217. p.mu.Unlock()
  218. client.Close()
  219. return
  220. }
  221. p.mu.Unlock()
  222. // Clear deadline
  223. client.SetDeadline(time.Time{})
  224. select {
  225. case p.pool <- client:
  226. // Returned to pool
  227. default:
  228. // Pool full, close connection
  229. client.Close()
  230. }
  231. }
  232. // Close closes all connections in the pool.
  233. func (p *KVPool) Close() error {
  234. p.mu.Lock()
  235. if p.closed {
  236. p.mu.Unlock()
  237. return nil
  238. }
  239. p.closed = true
  240. p.mu.Unlock()
  241. close(p.pool)
  242. for client := range p.pool {
  243. if client != nil {
  244. client.Close()
  245. }
  246. }
  247. return nil
  248. }
  249. // WithClient executes a function with a pooled connection.
  250. func (p *KVPool) WithClient(fn func(*KVClient) error) error {
  251. client, err := p.Get()
  252. if err != nil {
  253. return err
  254. }
  255. defer p.Put(client)
  256. return fn(client)
  257. }