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.

325 lines
6.1 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. // +build cleveldb
  2. package db
  3. import (
  4. "bytes"
  5. "fmt"
  6. "path/filepath"
  7. "github.com/jmhodges/levigo"
  8. )
  9. func init() {
  10. dbCreator := func(name string, dir string) (DB, error) {
  11. return NewCLevelDB(name, dir)
  12. }
  13. registerDBCreator(CLevelDBBackend, dbCreator, false)
  14. }
  15. var _ DB = (*CLevelDB)(nil)
  16. type CLevelDB struct {
  17. db *levigo.DB
  18. ro *levigo.ReadOptions
  19. wo *levigo.WriteOptions
  20. woSync *levigo.WriteOptions
  21. }
  22. func NewCLevelDB(name string, dir string) (*CLevelDB, error) {
  23. dbPath := filepath.Join(dir, name+".db")
  24. opts := levigo.NewOptions()
  25. opts.SetCache(levigo.NewLRUCache(1 << 30))
  26. opts.SetCreateIfMissing(true)
  27. db, err := levigo.Open(dbPath, opts)
  28. if err != nil {
  29. return nil, err
  30. }
  31. ro := levigo.NewReadOptions()
  32. wo := levigo.NewWriteOptions()
  33. woSync := levigo.NewWriteOptions()
  34. woSync.SetSync(true)
  35. database := &CLevelDB{
  36. db: db,
  37. ro: ro,
  38. wo: wo,
  39. woSync: woSync,
  40. }
  41. return database, nil
  42. }
  43. // Implements DB.
  44. func (db *CLevelDB) Get(key []byte) []byte {
  45. key = nonNilBytes(key)
  46. res, err := db.db.Get(db.ro, key)
  47. if err != nil {
  48. panic(err)
  49. }
  50. return res
  51. }
  52. // Implements DB.
  53. func (db *CLevelDB) Has(key []byte) bool {
  54. return db.Get(key) != nil
  55. }
  56. // Implements DB.
  57. func (db *CLevelDB) Set(key []byte, value []byte) {
  58. key = nonNilBytes(key)
  59. value = nonNilBytes(value)
  60. err := db.db.Put(db.wo, key, value)
  61. if err != nil {
  62. panic(err)
  63. }
  64. }
  65. // Implements DB.
  66. func (db *CLevelDB) SetSync(key []byte, value []byte) {
  67. key = nonNilBytes(key)
  68. value = nonNilBytes(value)
  69. err := db.db.Put(db.woSync, key, value)
  70. if err != nil {
  71. panic(err)
  72. }
  73. }
  74. // Implements DB.
  75. func (db *CLevelDB) Delete(key []byte) {
  76. key = nonNilBytes(key)
  77. err := db.db.Delete(db.wo, key)
  78. if err != nil {
  79. panic(err)
  80. }
  81. }
  82. // Implements DB.
  83. func (db *CLevelDB) DeleteSync(key []byte) {
  84. key = nonNilBytes(key)
  85. err := db.db.Delete(db.woSync, key)
  86. if err != nil {
  87. panic(err)
  88. }
  89. }
  90. func (db *CLevelDB) DB() *levigo.DB {
  91. return db.db
  92. }
  93. // Implements DB.
  94. func (db *CLevelDB) Close() {
  95. db.db.Close()
  96. db.ro.Close()
  97. db.wo.Close()
  98. db.woSync.Close()
  99. }
  100. // Implements DB.
  101. func (db *CLevelDB) Print() {
  102. itr := db.Iterator(nil, nil)
  103. defer itr.Close()
  104. for ; itr.Valid(); itr.Next() {
  105. key := itr.Key()
  106. value := itr.Value()
  107. fmt.Printf("[%X]:\t[%X]\n", key, value)
  108. }
  109. }
  110. // Implements DB.
  111. func (db *CLevelDB) Stats() map[string]string {
  112. keys := []string{
  113. "leveldb.aliveiters",
  114. "leveldb.alivesnaps",
  115. "leveldb.blockpool",
  116. "leveldb.cachedblock",
  117. "leveldb.num-files-at-level{n}",
  118. "leveldb.openedtables",
  119. "leveldb.sstables",
  120. "leveldb.stats",
  121. }
  122. stats := make(map[string]string, len(keys))
  123. for _, key := range keys {
  124. str := db.db.PropertyValue(key)
  125. stats[key] = str
  126. }
  127. return stats
  128. }
  129. //----------------------------------------
  130. // Batch
  131. // Implements DB.
  132. func (db *CLevelDB) NewBatch() Batch {
  133. batch := levigo.NewWriteBatch()
  134. return &cLevelDBBatch{db, batch}
  135. }
  136. type cLevelDBBatch struct {
  137. db *CLevelDB
  138. batch *levigo.WriteBatch
  139. }
  140. // Implements Batch.
  141. func (mBatch *cLevelDBBatch) Set(key, value []byte) {
  142. mBatch.batch.Put(key, value)
  143. }
  144. // Implements Batch.
  145. func (mBatch *cLevelDBBatch) Delete(key []byte) {
  146. mBatch.batch.Delete(key)
  147. }
  148. // Implements Batch.
  149. func (mBatch *cLevelDBBatch) Write() {
  150. err := mBatch.db.db.Write(mBatch.db.wo, mBatch.batch)
  151. if err != nil {
  152. panic(err)
  153. }
  154. }
  155. // Implements Batch.
  156. func (mBatch *cLevelDBBatch) WriteSync() {
  157. err := mBatch.db.db.Write(mBatch.db.woSync, mBatch.batch)
  158. if err != nil {
  159. panic(err)
  160. }
  161. }
  162. // Implements Batch.
  163. func (mBatch *cLevelDBBatch) Close() {
  164. mBatch.batch.Close()
  165. }
  166. //----------------------------------------
  167. // Iterator
  168. // NOTE This is almost identical to db/go_level_db.Iterator
  169. // Before creating a third version, refactor.
  170. func (db *CLevelDB) Iterator(start, end []byte) Iterator {
  171. itr := db.db.NewIterator(db.ro)
  172. return newCLevelDBIterator(itr, start, end, false)
  173. }
  174. func (db *CLevelDB) ReverseIterator(start, end []byte) Iterator {
  175. itr := db.db.NewIterator(db.ro)
  176. return newCLevelDBIterator(itr, start, end, true)
  177. }
  178. var _ Iterator = (*cLevelDBIterator)(nil)
  179. type cLevelDBIterator struct {
  180. source *levigo.Iterator
  181. start, end []byte
  182. isReverse bool
  183. isInvalid bool
  184. }
  185. func newCLevelDBIterator(source *levigo.Iterator, start, end []byte, isReverse bool) *cLevelDBIterator {
  186. if isReverse {
  187. if end == nil {
  188. source.SeekToLast()
  189. } else {
  190. source.Seek(end)
  191. if source.Valid() {
  192. eoakey := source.Key() // end or after key
  193. if bytes.Compare(end, eoakey) <= 0 {
  194. source.Prev()
  195. }
  196. } else {
  197. source.SeekToLast()
  198. }
  199. }
  200. } else {
  201. if start == nil {
  202. source.SeekToFirst()
  203. } else {
  204. source.Seek(start)
  205. }
  206. }
  207. return &cLevelDBIterator{
  208. source: source,
  209. start: start,
  210. end: end,
  211. isReverse: isReverse,
  212. isInvalid: false,
  213. }
  214. }
  215. func (itr cLevelDBIterator) Domain() ([]byte, []byte) {
  216. return itr.start, itr.end
  217. }
  218. func (itr cLevelDBIterator) Valid() bool {
  219. // Once invalid, forever invalid.
  220. if itr.isInvalid {
  221. return false
  222. }
  223. // Panic on DB error. No way to recover.
  224. itr.assertNoError()
  225. // If source is invalid, invalid.
  226. if !itr.source.Valid() {
  227. itr.isInvalid = true
  228. return false
  229. }
  230. // If key is end or past it, invalid.
  231. var start = itr.start
  232. var end = itr.end
  233. var key = itr.source.Key()
  234. if itr.isReverse {
  235. if start != nil && bytes.Compare(key, start) < 0 {
  236. itr.isInvalid = true
  237. return false
  238. }
  239. } else {
  240. if end != nil && bytes.Compare(end, key) <= 0 {
  241. itr.isInvalid = true
  242. return false
  243. }
  244. }
  245. // It's valid.
  246. return true
  247. }
  248. func (itr cLevelDBIterator) Key() []byte {
  249. itr.assertNoError()
  250. itr.assertIsValid()
  251. return itr.source.Key()
  252. }
  253. func (itr cLevelDBIterator) Value() []byte {
  254. itr.assertNoError()
  255. itr.assertIsValid()
  256. return itr.source.Value()
  257. }
  258. func (itr cLevelDBIterator) Next() {
  259. itr.assertNoError()
  260. itr.assertIsValid()
  261. if itr.isReverse {
  262. itr.source.Prev()
  263. } else {
  264. itr.source.Next()
  265. }
  266. }
  267. func (itr cLevelDBIterator) Close() {
  268. itr.source.Close()
  269. }
  270. func (itr cLevelDBIterator) assertNoError() {
  271. if err := itr.source.GetError(); err != nil {
  272. panic(err)
  273. }
  274. }
  275. func (itr cLevelDBIterator) assertIsValid() {
  276. if !itr.Valid() {
  277. panic("cLevelDBIterator is invalid")
  278. }
  279. }