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.

312 lines
5.9 KiB

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