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.

507 lines
8.4 KiB

  1. // Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
  2. // All rights reserved.
  3. //
  4. // Use of this source code is governed by a BSD-style license that can be
  5. // found in the LICENSE file.
  6. package leveldb
  7. import (
  8. "bytes"
  9. "fmt"
  10. "math/rand"
  11. "os"
  12. "path/filepath"
  13. "runtime"
  14. "sync/atomic"
  15. "testing"
  16. "github.com/syndtr/goleveldb/leveldb/iterator"
  17. "github.com/syndtr/goleveldb/leveldb/opt"
  18. "github.com/syndtr/goleveldb/leveldb/storage"
  19. )
  20. func randomString(r *rand.Rand, n int) []byte {
  21. b := new(bytes.Buffer)
  22. for i := 0; i < n; i++ {
  23. b.WriteByte(' ' + byte(r.Intn(95)))
  24. }
  25. return b.Bytes()
  26. }
  27. func compressibleStr(r *rand.Rand, frac float32, n int) []byte {
  28. nn := int(float32(n) * frac)
  29. rb := randomString(r, nn)
  30. b := make([]byte, 0, n+nn)
  31. for len(b) < n {
  32. b = append(b, rb...)
  33. }
  34. return b[:n]
  35. }
  36. type valueGen struct {
  37. src []byte
  38. pos int
  39. }
  40. func newValueGen(frac float32) *valueGen {
  41. v := new(valueGen)
  42. r := rand.New(rand.NewSource(301))
  43. v.src = make([]byte, 0, 1048576+100)
  44. for len(v.src) < 1048576 {
  45. v.src = append(v.src, compressibleStr(r, frac, 100)...)
  46. }
  47. return v
  48. }
  49. func (v *valueGen) get(n int) []byte {
  50. if v.pos+n > len(v.src) {
  51. v.pos = 0
  52. }
  53. v.pos += n
  54. return v.src[v.pos-n : v.pos]
  55. }
  56. var benchDB = filepath.Join(os.TempDir(), fmt.Sprintf("goleveldbbench-%d", os.Getuid()))
  57. type dbBench struct {
  58. b *testing.B
  59. stor storage.Storage
  60. db *DB
  61. o *opt.Options
  62. ro *opt.ReadOptions
  63. wo *opt.WriteOptions
  64. keys, values [][]byte
  65. }
  66. func openDBBench(b *testing.B, noCompress bool) *dbBench {
  67. _, err := os.Stat(benchDB)
  68. if err == nil {
  69. err = os.RemoveAll(benchDB)
  70. if err != nil {
  71. b.Fatal("cannot remove old db: ", err)
  72. }
  73. }
  74. p := &dbBench{
  75. b: b,
  76. o: &opt.Options{},
  77. ro: &opt.ReadOptions{},
  78. wo: &opt.WriteOptions{},
  79. }
  80. p.stor, err = storage.OpenFile(benchDB, false)
  81. if err != nil {
  82. b.Fatal("cannot open stor: ", err)
  83. }
  84. if noCompress {
  85. p.o.Compression = opt.NoCompression
  86. }
  87. p.db, err = Open(p.stor, p.o)
  88. if err != nil {
  89. b.Fatal("cannot open db: ", err)
  90. }
  91. return p
  92. }
  93. func (p *dbBench) reopen() {
  94. p.db.Close()
  95. var err error
  96. p.db, err = Open(p.stor, p.o)
  97. if err != nil {
  98. p.b.Fatal("Reopen: got error: ", err)
  99. }
  100. }
  101. func (p *dbBench) populate(n int) {
  102. p.keys, p.values = make([][]byte, n), make([][]byte, n)
  103. v := newValueGen(0.5)
  104. for i := range p.keys {
  105. p.keys[i], p.values[i] = []byte(fmt.Sprintf("%016d", i)), v.get(100)
  106. }
  107. }
  108. func (p *dbBench) randomize() {
  109. m := len(p.keys)
  110. times := m * 2
  111. r1, r2 := rand.New(rand.NewSource(0xdeadbeef)), rand.New(rand.NewSource(0xbeefface))
  112. for n := 0; n < times; n++ {
  113. i, j := r1.Int()%m, r2.Int()%m
  114. if i == j {
  115. continue
  116. }
  117. p.keys[i], p.keys[j] = p.keys[j], p.keys[i]
  118. p.values[i], p.values[j] = p.values[j], p.values[i]
  119. }
  120. }
  121. func (p *dbBench) writes(perBatch int) {
  122. b := p.b
  123. db := p.db
  124. n := len(p.keys)
  125. m := n / perBatch
  126. if n%perBatch > 0 {
  127. m++
  128. }
  129. batches := make([]Batch, m)
  130. j := 0
  131. for i := range batches {
  132. first := true
  133. for ; j < n && ((j+1)%perBatch != 0 || first); j++ {
  134. first = false
  135. batches[i].Put(p.keys[j], p.values[j])
  136. }
  137. }
  138. runtime.GC()
  139. b.ResetTimer()
  140. b.StartTimer()
  141. for i := range batches {
  142. err := db.Write(&(batches[i]), p.wo)
  143. if err != nil {
  144. b.Fatal("write failed: ", err)
  145. }
  146. }
  147. b.StopTimer()
  148. b.SetBytes(116)
  149. }
  150. func (p *dbBench) gc() {
  151. p.keys, p.values = nil, nil
  152. runtime.GC()
  153. }
  154. func (p *dbBench) puts() {
  155. b := p.b
  156. db := p.db
  157. b.ResetTimer()
  158. b.StartTimer()
  159. for i := range p.keys {
  160. err := db.Put(p.keys[i], p.values[i], p.wo)
  161. if err != nil {
  162. b.Fatal("put failed: ", err)
  163. }
  164. }
  165. b.StopTimer()
  166. b.SetBytes(116)
  167. }
  168. func (p *dbBench) fill() {
  169. b := p.b
  170. db := p.db
  171. perBatch := 10000
  172. batch := new(Batch)
  173. for i, n := 0, len(p.keys); i < n; {
  174. first := true
  175. for ; i < n && ((i+1)%perBatch != 0 || first); i++ {
  176. first = false
  177. batch.Put(p.keys[i], p.values[i])
  178. }
  179. err := db.Write(batch, p.wo)
  180. if err != nil {
  181. b.Fatal("write failed: ", err)
  182. }
  183. batch.Reset()
  184. }
  185. }
  186. func (p *dbBench) gets() {
  187. b := p.b
  188. db := p.db
  189. b.ResetTimer()
  190. for i := range p.keys {
  191. _, err := db.Get(p.keys[i], p.ro)
  192. if err != nil {
  193. b.Error("got error: ", err)
  194. }
  195. }
  196. b.StopTimer()
  197. }
  198. func (p *dbBench) seeks() {
  199. b := p.b
  200. iter := p.newIter()
  201. defer iter.Release()
  202. b.ResetTimer()
  203. for i := range p.keys {
  204. if !iter.Seek(p.keys[i]) {
  205. b.Error("value not found for: ", string(p.keys[i]))
  206. }
  207. }
  208. b.StopTimer()
  209. }
  210. func (p *dbBench) newIter() iterator.Iterator {
  211. iter := p.db.NewIterator(nil, p.ro)
  212. err := iter.Error()
  213. if err != nil {
  214. p.b.Fatal("cannot create iterator: ", err)
  215. }
  216. return iter
  217. }
  218. func (p *dbBench) close() {
  219. if bp, err := p.db.GetProperty("leveldb.blockpool"); err == nil {
  220. p.b.Log("Block pool stats: ", bp)
  221. }
  222. p.db.Close()
  223. p.stor.Close()
  224. os.RemoveAll(benchDB)
  225. p.db = nil
  226. p.keys = nil
  227. p.values = nil
  228. runtime.GC()
  229. }
  230. func BenchmarkDBWrite(b *testing.B) {
  231. p := openDBBench(b, false)
  232. p.populate(b.N)
  233. p.writes(1)
  234. p.close()
  235. }
  236. func BenchmarkDBWriteBatch(b *testing.B) {
  237. p := openDBBench(b, false)
  238. p.populate(b.N)
  239. p.writes(1000)
  240. p.close()
  241. }
  242. func BenchmarkDBWriteUncompressed(b *testing.B) {
  243. p := openDBBench(b, true)
  244. p.populate(b.N)
  245. p.writes(1)
  246. p.close()
  247. }
  248. func BenchmarkDBWriteBatchUncompressed(b *testing.B) {
  249. p := openDBBench(b, true)
  250. p.populate(b.N)
  251. p.writes(1000)
  252. p.close()
  253. }
  254. func BenchmarkDBWriteRandom(b *testing.B) {
  255. p := openDBBench(b, false)
  256. p.populate(b.N)
  257. p.randomize()
  258. p.writes(1)
  259. p.close()
  260. }
  261. func BenchmarkDBWriteRandomSync(b *testing.B) {
  262. p := openDBBench(b, false)
  263. p.wo.Sync = true
  264. p.populate(b.N)
  265. p.writes(1)
  266. p.close()
  267. }
  268. func BenchmarkDBOverwrite(b *testing.B) {
  269. p := openDBBench(b, false)
  270. p.populate(b.N)
  271. p.writes(1)
  272. p.writes(1)
  273. p.close()
  274. }
  275. func BenchmarkDBOverwriteRandom(b *testing.B) {
  276. p := openDBBench(b, false)
  277. p.populate(b.N)
  278. p.writes(1)
  279. p.randomize()
  280. p.writes(1)
  281. p.close()
  282. }
  283. func BenchmarkDBPut(b *testing.B) {
  284. p := openDBBench(b, false)
  285. p.populate(b.N)
  286. p.puts()
  287. p.close()
  288. }
  289. func BenchmarkDBRead(b *testing.B) {
  290. p := openDBBench(b, false)
  291. p.populate(b.N)
  292. p.fill()
  293. p.gc()
  294. iter := p.newIter()
  295. b.ResetTimer()
  296. for iter.Next() {
  297. }
  298. iter.Release()
  299. b.StopTimer()
  300. b.SetBytes(116)
  301. p.close()
  302. }
  303. func BenchmarkDBReadGC(b *testing.B) {
  304. p := openDBBench(b, false)
  305. p.populate(b.N)
  306. p.fill()
  307. iter := p.newIter()
  308. b.ResetTimer()
  309. for iter.Next() {
  310. }
  311. iter.Release()
  312. b.StopTimer()
  313. b.SetBytes(116)
  314. p.close()
  315. }
  316. func BenchmarkDBReadUncompressed(b *testing.B) {
  317. p := openDBBench(b, true)
  318. p.populate(b.N)
  319. p.fill()
  320. p.gc()
  321. iter := p.newIter()
  322. b.ResetTimer()
  323. for iter.Next() {
  324. }
  325. iter.Release()
  326. b.StopTimer()
  327. b.SetBytes(116)
  328. p.close()
  329. }
  330. func BenchmarkDBReadTable(b *testing.B) {
  331. p := openDBBench(b, false)
  332. p.populate(b.N)
  333. p.fill()
  334. p.reopen()
  335. p.gc()
  336. iter := p.newIter()
  337. b.ResetTimer()
  338. for iter.Next() {
  339. }
  340. iter.Release()
  341. b.StopTimer()
  342. b.SetBytes(116)
  343. p.close()
  344. }
  345. func BenchmarkDBReadReverse(b *testing.B) {
  346. p := openDBBench(b, false)
  347. p.populate(b.N)
  348. p.fill()
  349. p.gc()
  350. iter := p.newIter()
  351. b.ResetTimer()
  352. iter.Last()
  353. for iter.Prev() {
  354. }
  355. iter.Release()
  356. b.StopTimer()
  357. b.SetBytes(116)
  358. p.close()
  359. }
  360. func BenchmarkDBReadReverseTable(b *testing.B) {
  361. p := openDBBench(b, false)
  362. p.populate(b.N)
  363. p.fill()
  364. p.reopen()
  365. p.gc()
  366. iter := p.newIter()
  367. b.ResetTimer()
  368. iter.Last()
  369. for iter.Prev() {
  370. }
  371. iter.Release()
  372. b.StopTimer()
  373. b.SetBytes(116)
  374. p.close()
  375. }
  376. func BenchmarkDBSeek(b *testing.B) {
  377. p := openDBBench(b, false)
  378. p.populate(b.N)
  379. p.fill()
  380. p.seeks()
  381. p.close()
  382. }
  383. func BenchmarkDBSeekRandom(b *testing.B) {
  384. p := openDBBench(b, false)
  385. p.populate(b.N)
  386. p.fill()
  387. p.randomize()
  388. p.seeks()
  389. p.close()
  390. }
  391. func BenchmarkDBGet(b *testing.B) {
  392. p := openDBBench(b, false)
  393. p.populate(b.N)
  394. p.fill()
  395. p.gets()
  396. p.close()
  397. }
  398. func BenchmarkDBGetRandom(b *testing.B) {
  399. p := openDBBench(b, false)
  400. p.populate(b.N)
  401. p.fill()
  402. p.randomize()
  403. p.gets()
  404. p.close()
  405. }
  406. func BenchmarkDBReadConcurrent(b *testing.B) {
  407. p := openDBBench(b, false)
  408. p.populate(b.N)
  409. p.fill()
  410. p.gc()
  411. defer p.close()
  412. b.ResetTimer()
  413. b.SetBytes(116)
  414. b.RunParallel(func(pb *testing.PB) {
  415. iter := p.newIter()
  416. defer iter.Release()
  417. for pb.Next() && iter.Next() {
  418. }
  419. })
  420. }
  421. func BenchmarkDBReadConcurrent2(b *testing.B) {
  422. p := openDBBench(b, false)
  423. p.populate(b.N)
  424. p.fill()
  425. p.gc()
  426. defer p.close()
  427. b.ResetTimer()
  428. b.SetBytes(116)
  429. var dir uint32
  430. b.RunParallel(func(pb *testing.PB) {
  431. iter := p.newIter()
  432. defer iter.Release()
  433. if atomic.AddUint32(&dir, 1)%2 == 0 {
  434. for pb.Next() && iter.Next() {
  435. }
  436. } else {
  437. if pb.Next() && iter.Last() {
  438. for pb.Next() && iter.Prev() {
  439. }
  440. }
  441. }
  442. })
  443. }