1 // Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
2 // All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
20 . "github.com/onsi/gomega"
22 "github.com/syndtr/goleveldb/leveldb/storage"
35 ModeOpen StorageMode = 1 << iota
67 const flattenCount = modeCount * typeCount
69 func flattenType(m StorageMode, t storage.FileType) int {
89 panic("invalid storage mode")
93 case storage.TypeManifest:
94 return x + typeManifest
95 case storage.TypeJournal:
96 return x + typeJournal
97 case storage.TypeTable:
99 case storage.TypeTemp:
102 panic("invalid file type")
106 func listFlattenType(m StorageMode, t storage.FileType) []int {
107 ret := make([]int, 0, flattenCount)
111 case t&storage.TypeManifest != 0:
112 ret = append(ret, x+typeManifest)
113 case t&storage.TypeJournal != 0:
114 ret = append(ret, x+typeJournal)
115 case t&storage.TypeTable != 0:
116 ret = append(ret, x+typeTable)
117 case t&storage.TypeTemp != 0:
118 ret = append(ret, x+typeTemp)
122 case m&ModeOpen != 0:
124 case m&ModeCreate != 0:
126 case m&ModeRemove != 0:
128 case m&ModeRename != 0:
130 case m&ModeRead != 0:
132 case m&ModeWrite != 0:
134 case m&ModeSync != 0:
136 case m&ModeClose != 0:
142 func packFile(fd storage.FileDesc) uint64 {
143 if fd.Num>>(63-typeCount) != 0 {
146 return uint64(fd.Num<<typeCount) | uint64(fd.Type)
149 func unpackFile(x uint64) storage.FileDesc {
150 return storage.FileDesc{storage.FileType(x) & storage.TypeAll, int64(x >> typeCount)}
153 type emulatedError struct {
157 func (err emulatedError) Error() string {
158 return fmt.Sprintf("emulated storage error: %v", err.err)
161 type storageLock struct {
166 func (l storageLock) Unlock() {
168 l.s.logI("storage lock released")
177 func (r *reader) Read(p []byte) (n int, err error) {
178 err = r.s.emulateError(ModeRead, r.fd.Type)
180 r.s.stall(ModeRead, r.fd.Type)
181 n, err = r.Reader.Read(p)
183 r.s.count(ModeRead, r.fd.Type, n)
184 if err != nil && err != io.EOF {
185 r.s.logI("read error, fd=%s n=%d err=%v", r.fd, n, err)
190 func (r *reader) ReadAt(p []byte, off int64) (n int, err error) {
191 err = r.s.emulateError(ModeRead, r.fd.Type)
193 r.s.stall(ModeRead, r.fd.Type)
194 n, err = r.Reader.ReadAt(p, off)
196 r.s.count(ModeRead, r.fd.Type, n)
197 if err != nil && err != io.EOF {
198 r.s.logI("readAt error, fd=%s offset=%d n=%d err=%v", r.fd, off, n, err)
203 func (r *reader) Close() (err error) {
204 return r.s.fileClose(r.fd, r.Reader)
213 func (w *writer) Write(p []byte) (n int, err error) {
214 err = w.s.emulateError(ModeWrite, w.fd.Type)
216 w.s.stall(ModeWrite, w.fd.Type)
217 n, err = w.Writer.Write(p)
219 w.s.count(ModeWrite, w.fd.Type, n)
220 if err != nil && err != io.EOF {
221 w.s.logI("write error, fd=%s n=%d err=%v", w.fd, n, err)
226 func (w *writer) Sync() (err error) {
227 err = w.s.emulateError(ModeSync, w.fd.Type)
229 w.s.stall(ModeSync, w.fd.Type)
230 err = w.Writer.Sync()
232 w.s.count(ModeSync, w.fd.Type, 0)
234 w.s.logI("sync error, fd=%s err=%v", w.fd, err)
239 func (w *writer) Close() (err error) {
240 return w.s.fileClose(w.fd, w.Writer)
243 type Storage struct {
246 onClose func() (preserve bool, err error)
247 onLog func(str string)
254 // Open files, true=writer, false=reader
255 opens map[uint64]bool
256 counters [flattenCount]int
257 bytesCounter [flattenCount]int64
258 emulatedError [flattenCount]error
259 emulatedErrorOnce [flattenCount]bool
260 emulatedRandomError [flattenCount]error
261 emulatedRandomErrorProb [flattenCount]float64
263 stalled [flattenCount]bool
266 func (s *Storage) log(skip int, str string) {
269 _, file, line, ok := runtime.Caller(skip + 2)
271 // Truncate file name at last file name separator.
272 if index := strings.LastIndex(file, "/"); index >= 0 {
273 file = file[index+1:]
274 } else if index = strings.LastIndex(file, "\\"); index >= 0 {
275 file = file[index+1:]
281 fmt.Fprintf(&s.lb, "%s:%d: ", file, line)
282 lines := strings.Split(str, "\n")
283 if l := len(lines); l > 1 && lines[l-1] == "" {
286 for i, line := range lines {
288 s.lb.WriteString("\n\t")
290 s.lb.WriteString(line)
293 s.onLog(s.lb.String())
300 func (s *Storage) logISkip(skip int, format string, args ...interface{}) {
301 pc, _, _, ok := runtime.Caller(skip + 1)
303 if f := runtime.FuncForPC(pc); f != nil {
305 if index := strings.LastIndex(fname, "."); index >= 0 {
306 fname = fname[index+1:]
308 format = fname + ": " + format
311 s.log(skip+1, fmt.Sprintf(format, args...))
314 func (s *Storage) logI(format string, args ...interface{}) {
315 s.logISkip(1, format, args...)
318 func (s *Storage) OnLog(onLog func(log string)) {
323 s.onLog(log[:len(log)-1])
329 func (s *Storage) Log(str string) {
330 s.log(1, "Log: "+str)
334 func (s *Storage) Lock() (l storage.Locker, err error) {
335 l, err = s.Storage.Lock()
337 s.logI("storage locking failed, err=%v", err)
339 s.logI("storage locked")
340 l = storageLock{s, l}
345 func (s *Storage) List(t storage.FileType) (fds []storage.FileDesc, err error) {
346 fds, err = s.Storage.List(t)
348 s.logI("list failed, err=%v", err)
351 s.logI("list, type=0x%x count=%d", int(t), len(fds))
355 func (s *Storage) GetMeta() (fd storage.FileDesc, err error) {
356 fd, err = s.Storage.GetMeta()
358 if !os.IsNotExist(err) {
359 s.logI("get meta failed, err=%v", err)
363 s.logI("get meta, fd=%s", fd)
367 func (s *Storage) SetMeta(fd storage.FileDesc) error {
368 ExpectWithOffset(1, fd.Type).To(Equal(storage.TypeManifest))
369 err := s.Storage.SetMeta(fd)
371 s.logI("set meta failed, fd=%s err=%v", fd, err)
373 s.logI("set meta, fd=%s", fd)
378 func (s *Storage) fileClose(fd storage.FileDesc, closer io.Closer) (err error) {
379 err = s.emulateError(ModeClose, fd.Type)
381 s.stall(ModeClose, fd.Type)
387 ExpectWithOffset(2, s.opens).To(HaveKey(x), "File closed, fd=%s", fd)
390 s.countNB(ModeClose, fd.Type, 0)
393 s.logISkip(1, "file close failed, fd=%s writer=%v err=%v", fd, writer, err)
395 s.logISkip(1, "file closed, fd=%s writer=%v", fd, writer)
401 func (s *Storage) assertOpen(fd storage.FileDesc) {
403 ExpectWithOffset(2, s.opens).NotTo(HaveKey(x), "File open, fd=%s writer=%v", fd, s.opens[x])
406 func (s *Storage) Open(fd storage.FileDesc) (r storage.Reader, err error) {
407 err = s.emulateError(ModeOpen, fd.Type)
409 s.stall(ModeOpen, fd.Type)
415 s.countNB(ModeOpen, fd.Type, 0)
416 r, err = s.Storage.Open(fd)
419 s.logI("file open failed, fd=%s err=%v", fd, err)
421 s.logI("file opened, fd=%s", fd)
422 s.opens[packFile(fd)] = false
423 r = &reader{s, fd, r}
428 func (s *Storage) Create(fd storage.FileDesc) (w storage.Writer, err error) {
429 err = s.emulateError(ModeCreate, fd.Type)
431 s.stall(ModeCreate, fd.Type)
437 s.countNB(ModeCreate, fd.Type, 0)
438 w, err = s.Storage.Create(fd)
441 s.logI("file create failed, fd=%s err=%v", fd, err)
443 s.logI("file created, fd=%s", fd)
444 s.opens[packFile(fd)] = true
445 w = &writer{s, fd, w}
450 func (s *Storage) Remove(fd storage.FileDesc) (err error) {
451 err = s.emulateError(ModeRemove, fd.Type)
453 s.stall(ModeRemove, fd.Type)
459 s.countNB(ModeRemove, fd.Type, 0)
460 err = s.Storage.Remove(fd)
463 s.logI("file remove failed, fd=%s err=%v", fd, err)
465 s.logI("file removed, fd=%s", fd)
470 func (s *Storage) ForceRemove(fd storage.FileDesc) (err error) {
471 s.countNB(ModeRemove, fd.Type, 0)
472 if err = s.Storage.Remove(fd); err != nil {
473 s.logI("file remove failed (forced), fd=%s err=%v", fd, err)
475 s.logI("file removed (forced), fd=%s", fd)
480 func (s *Storage) Rename(oldfd, newfd storage.FileDesc) (err error) {
481 err = s.emulateError(ModeRename, oldfd.Type)
483 s.stall(ModeRename, oldfd.Type)
490 s.countNB(ModeRename, oldfd.Type, 0)
491 err = s.Storage.Rename(oldfd, newfd)
494 s.logI("file rename failed, oldfd=%s newfd=%s err=%v", oldfd, newfd, err)
496 s.logI("file renamed, oldfd=%s newfd=%s", oldfd, newfd)
501 func (s *Storage) ForceRename(oldfd, newfd storage.FileDesc) (err error) {
502 s.countNB(ModeRename, oldfd.Type, 0)
503 if err = s.Storage.Rename(oldfd, newfd); err != nil {
504 s.logI("file rename failed (forced), oldfd=%s newfd=%s err=%v", oldfd, newfd, err)
506 s.logI("file renamed (forced), oldfd=%s newfd=%s", oldfd, newfd)
511 func (s *Storage) openFiles() string {
513 for x, writer := range s.opens {
515 out += fmt.Sprintf("\n ยท fd=%s writer=%v", fd, writer)
520 func (s *Storage) CloseCheck() {
523 ExpectWithOffset(1, s.opens).To(BeEmpty(), s.openFiles())
526 func (s *Storage) OnClose(onClose func() (preserve bool, err error)) {
532 func (s *Storage) Close() error {
535 ExpectWithOffset(1, s.opens).To(BeEmpty(), s.openFiles())
536 err := s.Storage.Close()
538 s.logI("storage closing failed, err=%v", err)
540 s.logI("storage closed")
543 if s.onClose != nil {
545 if preserve, err0 = s.onClose(); err0 != nil {
546 s.logI("onClose error, err=%v", err0)
550 if storageKeepFS || preserve {
551 s.logI("storage is preserved, path=%v", s.path)
553 if err1 := os.RemoveAll(s.path); err1 != nil {
554 s.logI("cannot remove storage, err=%v", err1)
556 s.logI("storage has been removed")
563 func (s *Storage) countNB(m StorageMode, t storage.FileType, n int) {
564 s.counters[flattenType(m, t)]++
565 s.bytesCounter[flattenType(m, t)] += int64(n)
568 func (s *Storage) count(m StorageMode, t storage.FileType, n int) {
574 func (s *Storage) ResetCounter(m StorageMode, t storage.FileType) {
575 for _, x := range listFlattenType(m, t) {
577 s.bytesCounter[x] = 0
581 func (s *Storage) Counter(m StorageMode, t storage.FileType) (count int, bytes int64) {
582 for _, x := range listFlattenType(m, t) {
583 count += s.counters[x]
584 bytes += s.bytesCounter[x]
589 func (s *Storage) emulateError(m StorageMode, t storage.FileType) error {
592 x := flattenType(m, t)
593 if err := s.emulatedError[x]; err != nil {
594 if s.emulatedErrorOnce[x] {
595 s.emulatedError[x] = nil
597 return emulatedError{err}
599 if err := s.emulatedRandomError[x]; err != nil && s.rand.Float64() < s.emulatedRandomErrorProb[x] {
600 return emulatedError{err}
605 func (s *Storage) EmulateError(m StorageMode, t storage.FileType, err error) {
608 for _, x := range listFlattenType(m, t) {
609 s.emulatedError[x] = err
610 s.emulatedErrorOnce[x] = false
614 func (s *Storage) EmulateErrorOnce(m StorageMode, t storage.FileType, err error) {
617 for _, x := range listFlattenType(m, t) {
618 s.emulatedError[x] = err
619 s.emulatedErrorOnce[x] = true
623 func (s *Storage) EmulateRandomError(m StorageMode, t storage.FileType, prob float64, err error) {
626 for _, x := range listFlattenType(m, t) {
627 s.emulatedRandomError[x] = err
628 s.emulatedRandomErrorProb[x] = prob
632 func (s *Storage) stall(m StorageMode, t storage.FileType) {
633 x := flattenType(m, t)
641 func (s *Storage) Stall(m StorageMode, t storage.FileType) {
644 for _, x := range listFlattenType(m, t) {
649 func (s *Storage) Release(m StorageMode, t storage.FileType) {
652 for _, x := range listFlattenType(m, t) {
655 s.stallCond.Broadcast()
658 func NewStorage() *Storage {
669 path = filepath.Join(os.TempDir(), fmt.Sprintf("goleveldb-test%d0%d0%d", os.Getuid(), os.Getpid(), num))
670 if _, err := os.Stat(path); os.IsNotExist(err) {
671 stor, err = storage.OpenFile(path, false)
672 ExpectWithOffset(1, err).NotTo(HaveOccurred(), "creating storage at %s", path)
677 stor = storage.NewMemStorage()
683 opens: make(map[uint64]bool),
685 s.stallCond.L = &s.mu
687 s.logI("using FS storage")
688 s.logI("storage path: %s", s.path)
690 s.logI("using MEM storage")