OSDN Git Service

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