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.

693 lines
15 KiB

  1. // Copyright (c) 2014, 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 testutil
  7. import (
  8. "bytes"
  9. "fmt"
  10. "io"
  11. "math/rand"
  12. "os"
  13. "path/filepath"
  14. "runtime"
  15. "strings"
  16. "sync"
  17. . "github.com/onsi/gomega"
  18. "github.com/syndtr/goleveldb/leveldb/storage"
  19. )
  20. var (
  21. storageMu sync.Mutex
  22. storageUseFS = true
  23. storageKeepFS = false
  24. storageNum int
  25. )
  26. type StorageMode int
  27. const (
  28. ModeOpen StorageMode = 1 << iota
  29. ModeCreate
  30. ModeRemove
  31. ModeRename
  32. ModeRead
  33. ModeWrite
  34. ModeSync
  35. ModeClose
  36. )
  37. const (
  38. modeOpen = iota
  39. modeCreate
  40. modeRemove
  41. modeRename
  42. modeRead
  43. modeWrite
  44. modeSync
  45. modeClose
  46. modeCount
  47. )
  48. const (
  49. typeManifest = iota
  50. typeJournal
  51. typeTable
  52. typeTemp
  53. typeCount
  54. )
  55. const flattenCount = modeCount * typeCount
  56. func flattenType(m StorageMode, t storage.FileType) int {
  57. var x int
  58. switch m {
  59. case ModeOpen:
  60. x = modeOpen
  61. case ModeCreate:
  62. x = modeCreate
  63. case ModeRemove:
  64. x = modeRemove
  65. case ModeRename:
  66. x = modeRename
  67. case ModeRead:
  68. x = modeRead
  69. case ModeWrite:
  70. x = modeWrite
  71. case ModeSync:
  72. x = modeSync
  73. case ModeClose:
  74. x = modeClose
  75. default:
  76. panic("invalid storage mode")
  77. }
  78. x *= typeCount
  79. switch t {
  80. case storage.TypeManifest:
  81. return x + typeManifest
  82. case storage.TypeJournal:
  83. return x + typeJournal
  84. case storage.TypeTable:
  85. return x + typeTable
  86. case storage.TypeTemp:
  87. return x + typeTemp
  88. default:
  89. panic("invalid file type")
  90. }
  91. }
  92. func listFlattenType(m StorageMode, t storage.FileType) []int {
  93. ret := make([]int, 0, flattenCount)
  94. add := func(x int) {
  95. x *= typeCount
  96. switch {
  97. case t&storage.TypeManifest != 0:
  98. ret = append(ret, x+typeManifest)
  99. case t&storage.TypeJournal != 0:
  100. ret = append(ret, x+typeJournal)
  101. case t&storage.TypeTable != 0:
  102. ret = append(ret, x+typeTable)
  103. case t&storage.TypeTemp != 0:
  104. ret = append(ret, x+typeTemp)
  105. }
  106. }
  107. switch {
  108. case m&ModeOpen != 0:
  109. add(modeOpen)
  110. case m&ModeCreate != 0:
  111. add(modeCreate)
  112. case m&ModeRemove != 0:
  113. add(modeRemove)
  114. case m&ModeRename != 0:
  115. add(modeRename)
  116. case m&ModeRead != 0:
  117. add(modeRead)
  118. case m&ModeWrite != 0:
  119. add(modeWrite)
  120. case m&ModeSync != 0:
  121. add(modeSync)
  122. case m&ModeClose != 0:
  123. add(modeClose)
  124. }
  125. return ret
  126. }
  127. func packFile(fd storage.FileDesc) uint64 {
  128. if fd.Num>>(63-typeCount) != 0 {
  129. panic("overflow")
  130. }
  131. return uint64(fd.Num<<typeCount) | uint64(fd.Type)
  132. }
  133. func unpackFile(x uint64) storage.FileDesc {
  134. return storage.FileDesc{storage.FileType(x) & storage.TypeAll, int64(x >> typeCount)}
  135. }
  136. type emulatedError struct {
  137. err error
  138. }
  139. func (err emulatedError) Error() string {
  140. return fmt.Sprintf("emulated storage error: %v", err.err)
  141. }
  142. type storageLock struct {
  143. s *Storage
  144. l storage.Locker
  145. }
  146. func (l storageLock) Unlock() {
  147. l.l.Unlock()
  148. l.s.logI("storage lock released")
  149. }
  150. type reader struct {
  151. s *Storage
  152. fd storage.FileDesc
  153. storage.Reader
  154. }
  155. func (r *reader) Read(p []byte) (n int, err error) {
  156. err = r.s.emulateError(ModeRead, r.fd.Type)
  157. if err == nil {
  158. r.s.stall(ModeRead, r.fd.Type)
  159. n, err = r.Reader.Read(p)
  160. }
  161. r.s.count(ModeRead, r.fd.Type, n)
  162. if err != nil && err != io.EOF {
  163. r.s.logI("read error, fd=%s n=%d err=%v", r.fd, n, err)
  164. }
  165. return
  166. }
  167. func (r *reader) ReadAt(p []byte, off int64) (n int, err error) {
  168. err = r.s.emulateError(ModeRead, r.fd.Type)
  169. if err == nil {
  170. r.s.stall(ModeRead, r.fd.Type)
  171. n, err = r.Reader.ReadAt(p, off)
  172. }
  173. r.s.count(ModeRead, r.fd.Type, n)
  174. if err != nil && err != io.EOF {
  175. r.s.logI("readAt error, fd=%s offset=%d n=%d err=%v", r.fd, off, n, err)
  176. }
  177. return
  178. }
  179. func (r *reader) Close() (err error) {
  180. return r.s.fileClose(r.fd, r.Reader)
  181. }
  182. type writer struct {
  183. s *Storage
  184. fd storage.FileDesc
  185. storage.Writer
  186. }
  187. func (w *writer) Write(p []byte) (n int, err error) {
  188. err = w.s.emulateError(ModeWrite, w.fd.Type)
  189. if err == nil {
  190. w.s.stall(ModeWrite, w.fd.Type)
  191. n, err = w.Writer.Write(p)
  192. }
  193. w.s.count(ModeWrite, w.fd.Type, n)
  194. if err != nil && err != io.EOF {
  195. w.s.logI("write error, fd=%s n=%d err=%v", w.fd, n, err)
  196. }
  197. return
  198. }
  199. func (w *writer) Sync() (err error) {
  200. err = w.s.emulateError(ModeSync, w.fd.Type)
  201. if err == nil {
  202. w.s.stall(ModeSync, w.fd.Type)
  203. err = w.Writer.Sync()
  204. }
  205. w.s.count(ModeSync, w.fd.Type, 0)
  206. if err != nil {
  207. w.s.logI("sync error, fd=%s err=%v", w.fd, err)
  208. }
  209. return
  210. }
  211. func (w *writer) Close() (err error) {
  212. return w.s.fileClose(w.fd, w.Writer)
  213. }
  214. type Storage struct {
  215. storage.Storage
  216. path string
  217. onClose func() (preserve bool, err error)
  218. onLog func(str string)
  219. lmu sync.Mutex
  220. lb bytes.Buffer
  221. mu sync.Mutex
  222. rand *rand.Rand
  223. // Open files, true=writer, false=reader
  224. opens map[uint64]bool
  225. counters [flattenCount]int
  226. bytesCounter [flattenCount]int64
  227. emulatedError [flattenCount]error
  228. emulatedErrorOnce [flattenCount]bool
  229. emulatedRandomError [flattenCount]error
  230. emulatedRandomErrorProb [flattenCount]float64
  231. stallCond sync.Cond
  232. stalled [flattenCount]bool
  233. }
  234. func (s *Storage) log(skip int, str string) {
  235. s.lmu.Lock()
  236. defer s.lmu.Unlock()
  237. _, file, line, ok := runtime.Caller(skip + 2)
  238. if ok {
  239. // Truncate file name at last file name separator.
  240. if index := strings.LastIndex(file, "/"); index >= 0 {
  241. file = file[index+1:]
  242. } else if index = strings.LastIndex(file, "\\"); index >= 0 {
  243. file = file[index+1:]
  244. }
  245. } else {
  246. file = "???"
  247. line = 1
  248. }
  249. fmt.Fprintf(&s.lb, "%s:%d: ", file, line)
  250. lines := strings.Split(str, "\n")
  251. if l := len(lines); l > 1 && lines[l-1] == "" {
  252. lines = lines[:l-1]
  253. }
  254. for i, line := range lines {
  255. if i > 0 {
  256. s.lb.WriteString("\n\t")
  257. }
  258. s.lb.WriteString(line)
  259. }
  260. if s.onLog != nil {
  261. s.onLog(s.lb.String())
  262. s.lb.Reset()
  263. } else {
  264. s.lb.WriteByte('\n')
  265. }
  266. }
  267. func (s *Storage) logISkip(skip int, format string, args ...interface{}) {
  268. pc, _, _, ok := runtime.Caller(skip + 1)
  269. if ok {
  270. if f := runtime.FuncForPC(pc); f != nil {
  271. fname := f.Name()
  272. if index := strings.LastIndex(fname, "."); index >= 0 {
  273. fname = fname[index+1:]
  274. }
  275. format = fname + ": " + format
  276. }
  277. }
  278. s.log(skip+1, fmt.Sprintf(format, args...))
  279. }
  280. func (s *Storage) logI(format string, args ...interface{}) {
  281. s.logISkip(1, format, args...)
  282. }
  283. func (s *Storage) OnLog(onLog func(log string)) {
  284. s.lmu.Lock()
  285. s.onLog = onLog
  286. if s.lb.Len() != 0 {
  287. log := s.lb.String()
  288. s.onLog(log[:len(log)-1])
  289. s.lb.Reset()
  290. }
  291. s.lmu.Unlock()
  292. }
  293. func (s *Storage) Log(str string) {
  294. s.log(1, "Log: "+str)
  295. s.Storage.Log(str)
  296. }
  297. func (s *Storage) Lock() (l storage.Locker, err error) {
  298. l, err = s.Storage.Lock()
  299. if err != nil {
  300. s.logI("storage locking failed, err=%v", err)
  301. } else {
  302. s.logI("storage locked")
  303. l = storageLock{s, l}
  304. }
  305. return
  306. }
  307. func (s *Storage) List(t storage.FileType) (fds []storage.FileDesc, err error) {
  308. fds, err = s.Storage.List(t)
  309. if err != nil {
  310. s.logI("list failed, err=%v", err)
  311. return
  312. }
  313. s.logI("list, type=0x%x count=%d", int(t), len(fds))
  314. return
  315. }
  316. func (s *Storage) GetMeta() (fd storage.FileDesc, err error) {
  317. fd, err = s.Storage.GetMeta()
  318. if err != nil {
  319. if !os.IsNotExist(err) {
  320. s.logI("get meta failed, err=%v", err)
  321. }
  322. return
  323. }
  324. s.logI("get meta, fd=%s", fd)
  325. return
  326. }
  327. func (s *Storage) SetMeta(fd storage.FileDesc) error {
  328. ExpectWithOffset(1, fd.Type).To(Equal(storage.TypeManifest))
  329. err := s.Storage.SetMeta(fd)
  330. if err != nil {
  331. s.logI("set meta failed, fd=%s err=%v", fd, err)
  332. } else {
  333. s.logI("set meta, fd=%s", fd)
  334. }
  335. return err
  336. }
  337. func (s *Storage) fileClose(fd storage.FileDesc, closer io.Closer) (err error) {
  338. err = s.emulateError(ModeClose, fd.Type)
  339. if err == nil {
  340. s.stall(ModeClose, fd.Type)
  341. }
  342. x := packFile(fd)
  343. s.mu.Lock()
  344. defer s.mu.Unlock()
  345. if err == nil {
  346. ExpectWithOffset(2, s.opens).To(HaveKey(x), "File closed, fd=%s", fd)
  347. err = closer.Close()
  348. }
  349. s.countNB(ModeClose, fd.Type, 0)
  350. writer := s.opens[x]
  351. if err != nil {
  352. s.logISkip(1, "file close failed, fd=%s writer=%v err=%v", fd, writer, err)
  353. } else {
  354. s.logISkip(1, "file closed, fd=%s writer=%v", fd, writer)
  355. delete(s.opens, x)
  356. }
  357. return
  358. }
  359. func (s *Storage) assertOpen(fd storage.FileDesc) {
  360. x := packFile(fd)
  361. ExpectWithOffset(2, s.opens).NotTo(HaveKey(x), "File open, fd=%s writer=%v", fd, s.opens[x])
  362. }
  363. func (s *Storage) Open(fd storage.FileDesc) (r storage.Reader, err error) {
  364. err = s.emulateError(ModeOpen, fd.Type)
  365. if err == nil {
  366. s.stall(ModeOpen, fd.Type)
  367. }
  368. s.mu.Lock()
  369. defer s.mu.Unlock()
  370. if err == nil {
  371. s.assertOpen(fd)
  372. s.countNB(ModeOpen, fd.Type, 0)
  373. r, err = s.Storage.Open(fd)
  374. }
  375. if err != nil {
  376. s.logI("file open failed, fd=%s err=%v", fd, err)
  377. } else {
  378. s.logI("file opened, fd=%s", fd)
  379. s.opens[packFile(fd)] = false
  380. r = &reader{s, fd, r}
  381. }
  382. return
  383. }
  384. func (s *Storage) Create(fd storage.FileDesc) (w storage.Writer, err error) {
  385. err = s.emulateError(ModeCreate, fd.Type)
  386. if err == nil {
  387. s.stall(ModeCreate, fd.Type)
  388. }
  389. s.mu.Lock()
  390. defer s.mu.Unlock()
  391. if err == nil {
  392. s.assertOpen(fd)
  393. s.countNB(ModeCreate, fd.Type, 0)
  394. w, err = s.Storage.Create(fd)
  395. }
  396. if err != nil {
  397. s.logI("file create failed, fd=%s err=%v", fd, err)
  398. } else {
  399. s.logI("file created, fd=%s", fd)
  400. s.opens[packFile(fd)] = true
  401. w = &writer{s, fd, w}
  402. }
  403. return
  404. }
  405. func (s *Storage) Remove(fd storage.FileDesc) (err error) {
  406. err = s.emulateError(ModeRemove, fd.Type)
  407. if err == nil {
  408. s.stall(ModeRemove, fd.Type)
  409. }
  410. s.mu.Lock()
  411. defer s.mu.Unlock()
  412. if err == nil {
  413. s.assertOpen(fd)
  414. s.countNB(ModeRemove, fd.Type, 0)
  415. err = s.Storage.Remove(fd)
  416. }
  417. if err != nil {
  418. s.logI("file remove failed, fd=%s err=%v", fd, err)
  419. } else {
  420. s.logI("file removed, fd=%s", fd)
  421. }
  422. return
  423. }
  424. func (s *Storage) ForceRemove(fd storage.FileDesc) (err error) {
  425. s.countNB(ModeRemove, fd.Type, 0)
  426. if err = s.Storage.Remove(fd); err != nil {
  427. s.logI("file remove failed (forced), fd=%s err=%v", fd, err)
  428. } else {
  429. s.logI("file removed (forced), fd=%s", fd)
  430. }
  431. return
  432. }
  433. func (s *Storage) Rename(oldfd, newfd storage.FileDesc) (err error) {
  434. err = s.emulateError(ModeRename, oldfd.Type)
  435. if err == nil {
  436. s.stall(ModeRename, oldfd.Type)
  437. }
  438. s.mu.Lock()
  439. defer s.mu.Unlock()
  440. if err == nil {
  441. s.assertOpen(oldfd)
  442. s.assertOpen(newfd)
  443. s.countNB(ModeRename, oldfd.Type, 0)
  444. err = s.Storage.Rename(oldfd, newfd)
  445. }
  446. if err != nil {
  447. s.logI("file rename failed, oldfd=%s newfd=%s err=%v", oldfd, newfd, err)
  448. } else {
  449. s.logI("file renamed, oldfd=%s newfd=%s", oldfd, newfd)
  450. }
  451. return
  452. }
  453. func (s *Storage) ForceRename(oldfd, newfd storage.FileDesc) (err error) {
  454. s.countNB(ModeRename, oldfd.Type, 0)
  455. if err = s.Storage.Rename(oldfd, newfd); err != nil {
  456. s.logI("file rename failed (forced), oldfd=%s newfd=%s err=%v", oldfd, newfd, err)
  457. } else {
  458. s.logI("file renamed (forced), oldfd=%s newfd=%s", oldfd, newfd)
  459. }
  460. return
  461. }
  462. func (s *Storage) openFiles() string {
  463. out := "Open files:"
  464. for x, writer := range s.opens {
  465. fd := unpackFile(x)
  466. out += fmt.Sprintf("\n · fd=%s writer=%v", fd, writer)
  467. }
  468. return out
  469. }
  470. func (s *Storage) CloseCheck() {
  471. s.mu.Lock()
  472. defer s.mu.Unlock()
  473. ExpectWithOffset(1, s.opens).To(BeEmpty(), s.openFiles())
  474. }
  475. func (s *Storage) OnClose(onClose func() (preserve bool, err error)) {
  476. s.mu.Lock()
  477. s.onClose = onClose
  478. s.mu.Unlock()
  479. }
  480. func (s *Storage) Close() error {
  481. s.mu.Lock()
  482. defer s.mu.Unlock()
  483. ExpectWithOffset(1, s.opens).To(BeEmpty(), s.openFiles())
  484. err := s.Storage.Close()
  485. if err != nil {
  486. s.logI("storage closing failed, err=%v", err)
  487. } else {
  488. s.logI("storage closed")
  489. }
  490. var preserve bool
  491. if s.onClose != nil {
  492. var err0 error
  493. if preserve, err0 = s.onClose(); err0 != nil {
  494. s.logI("onClose error, err=%v", err0)
  495. }
  496. }
  497. if s.path != "" {
  498. if storageKeepFS || preserve {
  499. s.logI("storage is preserved, path=%v", s.path)
  500. } else {
  501. if err1 := os.RemoveAll(s.path); err1 != nil {
  502. s.logI("cannot remove storage, err=%v", err1)
  503. } else {
  504. s.logI("storage has been removed")
  505. }
  506. }
  507. }
  508. return err
  509. }
  510. func (s *Storage) countNB(m StorageMode, t storage.FileType, n int) {
  511. s.counters[flattenType(m, t)]++
  512. s.bytesCounter[flattenType(m, t)] += int64(n)
  513. }
  514. func (s *Storage) count(m StorageMode, t storage.FileType, n int) {
  515. s.mu.Lock()
  516. defer s.mu.Unlock()
  517. s.countNB(m, t, n)
  518. }
  519. func (s *Storage) ResetCounter(m StorageMode, t storage.FileType) {
  520. for _, x := range listFlattenType(m, t) {
  521. s.counters[x] = 0
  522. s.bytesCounter[x] = 0
  523. }
  524. }
  525. func (s *Storage) Counter(m StorageMode, t storage.FileType) (count int, bytes int64) {
  526. for _, x := range listFlattenType(m, t) {
  527. count += s.counters[x]
  528. bytes += s.bytesCounter[x]
  529. }
  530. return
  531. }
  532. func (s *Storage) emulateError(m StorageMode, t storage.FileType) error {
  533. s.mu.Lock()
  534. defer s.mu.Unlock()
  535. x := flattenType(m, t)
  536. if err := s.emulatedError[x]; err != nil {
  537. if s.emulatedErrorOnce[x] {
  538. s.emulatedError[x] = nil
  539. }
  540. return emulatedError{err}
  541. }
  542. if err := s.emulatedRandomError[x]; err != nil && s.rand.Float64() < s.emulatedRandomErrorProb[x] {
  543. return emulatedError{err}
  544. }
  545. return nil
  546. }
  547. func (s *Storage) EmulateError(m StorageMode, t storage.FileType, err error) {
  548. s.mu.Lock()
  549. defer s.mu.Unlock()
  550. for _, x := range listFlattenType(m, t) {
  551. s.emulatedError[x] = err
  552. s.emulatedErrorOnce[x] = false
  553. }
  554. }
  555. func (s *Storage) EmulateErrorOnce(m StorageMode, t storage.FileType, err error) {
  556. s.mu.Lock()
  557. defer s.mu.Unlock()
  558. for _, x := range listFlattenType(m, t) {
  559. s.emulatedError[x] = err
  560. s.emulatedErrorOnce[x] = true
  561. }
  562. }
  563. func (s *Storage) EmulateRandomError(m StorageMode, t storage.FileType, prob float64, err error) {
  564. s.mu.Lock()
  565. defer s.mu.Unlock()
  566. for _, x := range listFlattenType(m, t) {
  567. s.emulatedRandomError[x] = err
  568. s.emulatedRandomErrorProb[x] = prob
  569. }
  570. }
  571. func (s *Storage) stall(m StorageMode, t storage.FileType) {
  572. x := flattenType(m, t)
  573. s.mu.Lock()
  574. defer s.mu.Unlock()
  575. for s.stalled[x] {
  576. s.stallCond.Wait()
  577. }
  578. }
  579. func (s *Storage) Stall(m StorageMode, t storage.FileType) {
  580. s.mu.Lock()
  581. defer s.mu.Unlock()
  582. for _, x := range listFlattenType(m, t) {
  583. s.stalled[x] = true
  584. }
  585. }
  586. func (s *Storage) Release(m StorageMode, t storage.FileType) {
  587. s.mu.Lock()
  588. defer s.mu.Unlock()
  589. for _, x := range listFlattenType(m, t) {
  590. s.stalled[x] = false
  591. }
  592. s.stallCond.Broadcast()
  593. }
  594. func NewStorage() *Storage {
  595. var (
  596. stor storage.Storage
  597. path string
  598. )
  599. if storageUseFS {
  600. for {
  601. storageMu.Lock()
  602. num := storageNum
  603. storageNum++
  604. storageMu.Unlock()
  605. path = filepath.Join(os.TempDir(), fmt.Sprintf("goleveldb-test%d0%d0%d", os.Getuid(), os.Getpid(), num))
  606. if _, err := os.Stat(path); os.IsNotExist(err) {
  607. stor, err = storage.OpenFile(path, false)
  608. ExpectWithOffset(1, err).NotTo(HaveOccurred(), "creating storage at %s", path)
  609. break
  610. }
  611. }
  612. } else {
  613. stor = storage.NewMemStorage()
  614. }
  615. s := &Storage{
  616. Storage: stor,
  617. path: path,
  618. rand: NewRand(),
  619. opens: make(map[uint64]bool),
  620. }
  621. s.stallCond.L = &s.mu
  622. if s.path != "" {
  623. s.logI("using FS storage")
  624. s.logI("storage path: %s", s.path)
  625. } else {
  626. s.logI("using MEM storage")
  627. }
  628. return s
  629. }