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