kv.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. package common
  2. import (
  3. "fmt"
  4. "github.com/patrickmn/go-cache"
  5. "os"
  6. "sync"
  7. )
  8. type KeyValue interface {
  9. Open() error
  10. Close() error
  11. Set(key string, value interface{}) error
  12. Replace(key string, value interface{}) error
  13. Get(key string) (interface{}, bool)
  14. Delete(key string) error
  15. Keys() (keys []string, err error)
  16. }
  17. type SyncKVMap struct {
  18. sync.RWMutex
  19. internal map[string]*SimpleKVStore
  20. }
  21. func (sm *SyncKVMap) Load(path string) (result *SimpleKVStore) {
  22. sm.Lock()
  23. defer sm.Unlock()
  24. if s, ok := sm.internal[path]; ok {
  25. result = s
  26. } else {
  27. c := cache.New(cache.NoExpiration, 0)
  28. if _, err := os.Stat(path); os.IsNotExist(err) {
  29. os.MkdirAll(path, os.ModePerm)
  30. }
  31. result = NewSimpleKVStore(path+"/stores.data", c)
  32. sm.internal[path] = result
  33. }
  34. return
  35. }
  36. var stores = &SyncKVMap{
  37. internal: make(map[string]*SimpleKVStore),
  38. }
  39. func GetSimpleKVStore(path string) *SimpleKVStore {
  40. return stores.Load(path)
  41. }
  42. type CtrlType int
  43. const (
  44. OPEN CtrlType = iota
  45. SAVE
  46. CLOSE
  47. )
  48. type SimpleKVStore struct {
  49. path string
  50. c *cache.Cache
  51. /* These 2 channels must be mapping one by one*/
  52. ctrlCh chan CtrlType
  53. errCh chan error
  54. }
  55. func NewSimpleKVStore(path string, c *cache.Cache) *SimpleKVStore {
  56. r := &SimpleKVStore{
  57. path: path,
  58. c: c,
  59. ctrlCh: make(chan CtrlType),
  60. errCh: make(chan error),
  61. }
  62. go r.run()
  63. return r
  64. }
  65. func (m *SimpleKVStore) run() {
  66. count := 0
  67. opened := false
  68. for c := range m.ctrlCh {
  69. switch c {
  70. case OPEN:
  71. count++
  72. if !opened {
  73. if _, err := os.Stat(m.path); os.IsNotExist(err) {
  74. m.errCh <- nil
  75. break
  76. }
  77. if e := m.c.LoadFile(m.path); e != nil {
  78. m.errCh <- e
  79. break
  80. }
  81. }
  82. m.errCh <- nil
  83. opened = true
  84. case CLOSE:
  85. count--
  86. if count == 0 {
  87. opened = false
  88. err := m.doClose()
  89. if err != nil {
  90. Log.Error(err)
  91. m.errCh <- err
  92. break
  93. }
  94. }
  95. m.errCh <- nil
  96. case SAVE:
  97. //swallow duplicate requests
  98. if len(m.ctrlCh) > 0 {
  99. m.errCh <- nil
  100. break
  101. }
  102. if e := m.c.SaveFile(m.path); e != nil {
  103. Log.Error(e)
  104. m.errCh <- e
  105. break
  106. }
  107. m.errCh <- nil
  108. }
  109. }
  110. }
  111. func (m *SimpleKVStore) Open() error {
  112. m.ctrlCh <- OPEN
  113. return <-m.errCh
  114. }
  115. func (m *SimpleKVStore) Close() error {
  116. m.ctrlCh <- CLOSE
  117. return <-m.errCh
  118. }
  119. func (m *SimpleKVStore) doClose() error {
  120. e := m.c.SaveFile(m.path)
  121. m.c.Flush() //Delete all of the values from memory.
  122. return e
  123. }
  124. func (m *SimpleKVStore) saveToFile() error {
  125. m.ctrlCh <- SAVE
  126. return <-m.errCh
  127. }
  128. func (m *SimpleKVStore) Set(key string, value interface{}) error {
  129. if m.c == nil {
  130. return fmt.Errorf("cache %s has not been initialized yet", m.path)
  131. }
  132. if err := m.c.Add(key, value, cache.NoExpiration); err != nil {
  133. return err
  134. }
  135. return m.saveToFile()
  136. }
  137. func (m *SimpleKVStore) Replace(key string, value interface{}) error {
  138. if m.c == nil {
  139. return fmt.Errorf("cache %s has not been initialized yet", m.path)
  140. }
  141. m.c.Set(key, value, cache.NoExpiration)
  142. return m.saveToFile()
  143. }
  144. func (m *SimpleKVStore) Get(key string) (interface{}, bool) {
  145. return m.c.Get(key)
  146. }
  147. func (m *SimpleKVStore) Delete(key string) error {
  148. if m.c == nil {
  149. return fmt.Errorf("cache %s has not been initialized yet", m.path)
  150. }
  151. if _, found := m.c.Get(key); found {
  152. m.c.Delete(key)
  153. } else {
  154. return fmt.Errorf("%s is not found", key)
  155. }
  156. return m.saveToFile()
  157. }
  158. func (m *SimpleKVStore) Keys() (keys []string, err error) {
  159. if m.c == nil {
  160. return nil, fmt.Errorf("Cache %s has not been initialized yet.", m.path)
  161. }
  162. its := m.c.Items()
  163. keys = make([]string, 0, len(its))
  164. for k := range its {
  165. keys = append(keys, k)
  166. }
  167. return keys, nil
  168. }