github.com/df-mc/goleveldb@v1.1.9/leveldb/storage/file_storage.go (about) 1 // Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com> 2 // All rights reservefs. 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 storage 8 9 import ( 10 "errors" 11 "fmt" 12 "io" 13 "io/ioutil" 14 "os" 15 "path/filepath" 16 "runtime" 17 "sort" 18 "strconv" 19 "strings" 20 "sync" 21 "time" 22 ) 23 24 var ( 25 errFileOpen = errors.New("leveldb/storage: file still open") 26 errReadOnly = errors.New("leveldb/storage: storage is read-only") 27 ) 28 29 type fileLock interface { 30 release() error 31 } 32 33 type fileStorageLock struct { 34 fs *fileStorage 35 } 36 37 func (lock *fileStorageLock) Unlock() { 38 if lock.fs != nil { 39 lock.fs.mu.Lock() 40 defer lock.fs.mu.Unlock() 41 if lock.fs.slock == lock { 42 lock.fs.slock = nil 43 } 44 } 45 } 46 47 type int64Slice []int64 48 49 func (p int64Slice) Len() int { return len(p) } 50 func (p int64Slice) Less(i, j int) bool { return p[i] < p[j] } 51 func (p int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 52 53 func writeFileSynced(filename string, data []byte, perm os.FileMode) error { 54 f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) 55 if err != nil { 56 return err 57 } 58 n, err := f.Write(data) 59 if err == nil && n < len(data) { 60 err = io.ErrShortWrite 61 } 62 if err1 := f.Sync(); err == nil { 63 err = err1 64 } 65 if err1 := f.Close(); err == nil { 66 err = err1 67 } 68 return err 69 } 70 71 const logSizeThreshold = 1024 * 1024 // 1 MiB 72 73 // fileStorage is a file-system backed storage. 74 type fileStorage struct { 75 path string 76 readOnly bool 77 78 mu sync.Mutex 79 flock fileLock 80 slock *fileStorageLock 81 logw *os.File 82 logSize int64 83 buf []byte 84 // Opened file counter; if open < 0 means closed. 85 open int 86 day int 87 } 88 89 // OpenFile returns a new filesystem-backed storage implementation with the given 90 // path. This also acquire a file lock, so any subsequent attempt to open the 91 // same path will fail. 92 // 93 // The storage must be closed after use, by calling Close method. 94 func OpenFile(path string, readOnly bool) (Storage, error) { 95 if fi, err := os.Stat(path); err == nil { 96 if !fi.IsDir() { 97 return nil, fmt.Errorf("leveldb/storage: open %s: not a directory", path) 98 } 99 } else if os.IsNotExist(err) && !readOnly { 100 if err := os.MkdirAll(path, 0755); err != nil { 101 return nil, err 102 } 103 } else { 104 return nil, err 105 } 106 107 flock, err := newFileLock(filepath.Join(path, "LOCK"), readOnly) 108 if err != nil { 109 return nil, err 110 } 111 112 defer func() { 113 if err != nil { 114 flock.release() 115 } 116 }() 117 118 var ( 119 logw *os.File 120 logSize int64 121 ) 122 if !readOnly { 123 logw, err = os.OpenFile(filepath.Join(path, "LOG"), os.O_WRONLY|os.O_CREATE, 0644) 124 if err != nil { 125 return nil, err 126 } 127 logSize, err = logw.Seek(0, os.SEEK_END) 128 if err != nil { 129 logw.Close() 130 return nil, err 131 } 132 } 133 134 fs := &fileStorage{ 135 path: path, 136 readOnly: readOnly, 137 flock: flock, 138 logw: logw, 139 logSize: logSize, 140 } 141 runtime.SetFinalizer(fs, (*fileStorage).Close) 142 return fs, nil 143 } 144 145 func (fs *fileStorage) Lock() (Locker, error) { 146 fs.mu.Lock() 147 defer fs.mu.Unlock() 148 if fs.open < 0 { 149 return nil, ErrClosed 150 } 151 if fs.readOnly { 152 return &fileStorageLock{}, nil 153 } 154 if fs.slock != nil { 155 return nil, ErrLocked 156 } 157 fs.slock = &fileStorageLock{fs: fs} 158 return fs.slock, nil 159 } 160 161 func itoa(buf []byte, i int, wid int) []byte { 162 u := uint(i) 163 if u == 0 && wid <= 1 { 164 return append(buf, '0') 165 } 166 167 // Assemble decimal in reverse order. 168 var b [32]byte 169 bp := len(b) 170 for ; u > 0 || wid > 0; u /= 10 { 171 bp-- 172 wid-- 173 b[bp] = byte(u%10) + '0' 174 } 175 return append(buf, b[bp:]...) 176 } 177 178 func (fs *fileStorage) printDay(t time.Time) { 179 if fs.day == t.Day() { 180 return 181 } 182 fs.day = t.Day() 183 fs.logw.Write([]byte("=============== " + t.Format("Jan 2, 2006 (MST)") + " ===============\n")) 184 } 185 186 func (fs *fileStorage) doLog(t time.Time, str string) { 187 if fs.logSize > logSizeThreshold { 188 // Rotate log file. 189 fs.logw.Close() 190 fs.logw = nil 191 fs.logSize = 0 192 rename(filepath.Join(fs.path, "LOG"), filepath.Join(fs.path, "LOG.old")) 193 } 194 if fs.logw == nil { 195 var err error 196 fs.logw, err = os.OpenFile(filepath.Join(fs.path, "LOG"), os.O_WRONLY|os.O_CREATE, 0644) 197 if err != nil { 198 return 199 } 200 // Force printDay on new log file. 201 fs.day = 0 202 } 203 fs.printDay(t) 204 hour, min, sec := t.Clock() 205 msec := t.Nanosecond() / 1e3 206 // time 207 fs.buf = itoa(fs.buf[:0], hour, 2) 208 fs.buf = append(fs.buf, ':') 209 fs.buf = itoa(fs.buf, min, 2) 210 fs.buf = append(fs.buf, ':') 211 fs.buf = itoa(fs.buf, sec, 2) 212 fs.buf = append(fs.buf, '.') 213 fs.buf = itoa(fs.buf, msec, 6) 214 fs.buf = append(fs.buf, ' ') 215 // write 216 fs.buf = append(fs.buf, []byte(str)...) 217 fs.buf = append(fs.buf, '\n') 218 n, _ := fs.logw.Write(fs.buf) 219 fs.logSize += int64(n) 220 } 221 222 func (fs *fileStorage) Log(str string) { 223 if !fs.readOnly { 224 t := time.Now() 225 fs.mu.Lock() 226 defer fs.mu.Unlock() 227 if fs.open < 0 { 228 return 229 } 230 fs.doLog(t, str) 231 } 232 } 233 234 func (fs *fileStorage) log(str string) { 235 if !fs.readOnly { 236 fs.doLog(time.Now(), str) 237 } 238 } 239 240 func (fs *fileStorage) setMeta(fd FileDesc) error { 241 content := fsGenName(fd) + "\n" 242 // Check and backup old CURRENT file. 243 currentPath := filepath.Join(fs.path, "CURRENT") 244 if _, err := os.Stat(currentPath); err == nil { 245 b, err := ioutil.ReadFile(currentPath) 246 if err != nil { 247 fs.log(fmt.Sprintf("backup CURRENT: %v", err)) 248 return err 249 } 250 if string(b) == content { 251 // Content not changed, do nothing. 252 return nil 253 } 254 if err := writeFileSynced(currentPath+".bak", b, 0644); err != nil { 255 fs.log(fmt.Sprintf("backup CURRENT: %v", err)) 256 return err 257 } 258 } else if !os.IsNotExist(err) { 259 return err 260 } 261 path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), fd.Num) 262 if err := writeFileSynced(path, []byte(content), 0644); err != nil { 263 fs.log(fmt.Sprintf("create CURRENT.%d: %v", fd.Num, err)) 264 return err 265 } 266 // Replace CURRENT file. 267 if err := rename(path, currentPath); err != nil { 268 fs.log(fmt.Sprintf("rename CURRENT.%d: %v", fd.Num, err)) 269 return err 270 } 271 // Sync root directory. 272 if err := syncDir(fs.path); err != nil { 273 fs.log(fmt.Sprintf("syncDir: %v", err)) 274 return err 275 } 276 return nil 277 } 278 279 func (fs *fileStorage) SetMeta(fd FileDesc) error { 280 if !FileDescOk(fd) { 281 return ErrInvalidFile 282 } 283 if fs.readOnly { 284 return errReadOnly 285 } 286 287 fs.mu.Lock() 288 defer fs.mu.Unlock() 289 if fs.open < 0 { 290 return ErrClosed 291 } 292 return fs.setMeta(fd) 293 } 294 295 func (fs *fileStorage) GetMeta() (FileDesc, error) { 296 fs.mu.Lock() 297 defer fs.mu.Unlock() 298 if fs.open < 0 { 299 return FileDesc{}, ErrClosed 300 } 301 dir, err := os.Open(fs.path) 302 if err != nil { 303 return FileDesc{}, err 304 } 305 names, err := dir.Readdirnames(0) 306 // Close the dir first before checking for Readdirnames error. 307 if ce := dir.Close(); ce != nil { 308 fs.log(fmt.Sprintf("close dir: %v", ce)) 309 } 310 if err != nil { 311 return FileDesc{}, err 312 } 313 // Try this in order: 314 // - CURRENT.[0-9]+ ('pending rename' file, descending order) 315 // - CURRENT 316 // - CURRENT.bak 317 // 318 // Skip corrupted file or file that point to a missing target file. 319 type currentFile struct { 320 name string 321 fd FileDesc 322 } 323 tryCurrent := func(name string) (*currentFile, error) { 324 b, err := ioutil.ReadFile(filepath.Join(fs.path, name)) 325 if err != nil { 326 if os.IsNotExist(err) { 327 err = os.ErrNotExist 328 } 329 return nil, err 330 } 331 var fd FileDesc 332 if len(b) < 1 || b[len(b)-1] != '\n' || !fsParseNamePtr(string(b[:len(b)-1]), &fd) { 333 fs.log(fmt.Sprintf("%s: corrupted content: %q", name, b)) 334 err := &ErrCorrupted{ 335 Err: errors.New("leveldb/storage: corrupted or incomplete CURRENT file"), 336 } 337 return nil, err 338 } 339 if _, err := os.Stat(filepath.Join(fs.path, fsGenName(fd))); err != nil { 340 if os.IsNotExist(err) { 341 fs.log(fmt.Sprintf("%s: missing target file: %s", name, fd)) 342 err = os.ErrNotExist 343 } 344 return nil, err 345 } 346 return ¤tFile{name: name, fd: fd}, nil 347 } 348 tryCurrents := func(names []string) (*currentFile, error) { 349 var ( 350 cur *currentFile 351 // Last corruption error. 352 lastCerr error 353 ) 354 for _, name := range names { 355 var err error 356 cur, err = tryCurrent(name) 357 if err == nil { 358 break 359 } else if err == os.ErrNotExist { 360 // Fallback to the next file. 361 } else if isCorrupted(err) { 362 lastCerr = err 363 // Fallback to the next file. 364 } else { 365 // In case the error is due to permission, etc. 366 return nil, err 367 } 368 } 369 if cur == nil { 370 err := os.ErrNotExist 371 if lastCerr != nil { 372 err = lastCerr 373 } 374 return nil, err 375 } 376 return cur, nil 377 } 378 379 // Try 'pending rename' files. 380 var nums []int64 381 for _, name := range names { 382 if strings.HasPrefix(name, "CURRENT.") && name != "CURRENT.bak" { 383 i, err := strconv.ParseInt(name[8:], 10, 64) 384 if err == nil { 385 nums = append(nums, i) 386 } 387 } 388 } 389 var ( 390 pendCur *currentFile 391 pendErr = os.ErrNotExist 392 pendNames []string 393 ) 394 if len(nums) > 0 { 395 sort.Sort(sort.Reverse(int64Slice(nums))) 396 pendNames = make([]string, len(nums)) 397 for i, num := range nums { 398 pendNames[i] = fmt.Sprintf("CURRENT.%d", num) 399 } 400 pendCur, pendErr = tryCurrents(pendNames) 401 if pendErr != nil && pendErr != os.ErrNotExist && !isCorrupted(pendErr) { 402 return FileDesc{}, pendErr 403 } 404 } 405 406 // Try CURRENT and CURRENT.bak. 407 curCur, curErr := tryCurrents([]string{"CURRENT", "CURRENT.bak"}) 408 if curErr != nil && curErr != os.ErrNotExist && !isCorrupted(curErr) { 409 return FileDesc{}, curErr 410 } 411 412 // pendCur takes precedence, but guards against obsolete pendCur. 413 if pendCur != nil && (curCur == nil || pendCur.fd.Num > curCur.fd.Num) { 414 curCur = pendCur 415 } 416 417 if curCur != nil { 418 // Restore CURRENT file to proper state. 419 if !fs.readOnly && (curCur.name != "CURRENT" || len(pendNames) != 0) { 420 // Ignore setMeta errors, however don't delete obsolete files if we 421 // catch error. 422 if err := fs.setMeta(curCur.fd); err == nil { 423 // Remove 'pending rename' files. 424 for _, name := range pendNames { 425 if err := os.Remove(filepath.Join(fs.path, name)); err != nil { 426 fs.log(fmt.Sprintf("remove %s: %v", name, err)) 427 } 428 } 429 } 430 } 431 return curCur.fd, nil 432 } 433 434 // Nothing found. 435 if isCorrupted(pendErr) { 436 return FileDesc{}, pendErr 437 } 438 return FileDesc{}, curErr 439 } 440 441 func (fs *fileStorage) List(ft FileType) (fds []FileDesc, err error) { 442 fs.mu.Lock() 443 defer fs.mu.Unlock() 444 if fs.open < 0 { 445 return nil, ErrClosed 446 } 447 dir, err := os.Open(fs.path) 448 if err != nil { 449 return 450 } 451 names, err := dir.Readdirnames(0) 452 // Close the dir first before checking for Readdirnames error. 453 if cerr := dir.Close(); cerr != nil { 454 fs.log(fmt.Sprintf("close dir: %v", cerr)) 455 } 456 if err == nil { 457 for _, name := range names { 458 if fd, ok := fsParseName(name); ok && fd.Type&ft != 0 { 459 fds = append(fds, fd) 460 } 461 } 462 } 463 return 464 } 465 466 func (fs *fileStorage) Open(fd FileDesc) (Reader, error) { 467 if !FileDescOk(fd) { 468 return nil, ErrInvalidFile 469 } 470 471 fs.mu.Lock() 472 defer fs.mu.Unlock() 473 if fs.open < 0 { 474 return nil, ErrClosed 475 } 476 of, err := os.OpenFile(filepath.Join(fs.path, fsGenName(fd)), os.O_RDONLY, 0) 477 if err != nil { 478 if fsHasOldName(fd) && os.IsNotExist(err) { 479 of, err = os.OpenFile(filepath.Join(fs.path, fsGenOldName(fd)), os.O_RDONLY, 0) 480 if err == nil { 481 goto ok 482 } 483 } 484 return nil, err 485 } 486 ok: 487 fs.open++ 488 return &fileWrap{File: of, fs: fs, fd: fd}, nil 489 } 490 491 func (fs *fileStorage) Create(fd FileDesc) (Writer, error) { 492 if !FileDescOk(fd) { 493 return nil, ErrInvalidFile 494 } 495 if fs.readOnly { 496 return nil, errReadOnly 497 } 498 499 fs.mu.Lock() 500 defer fs.mu.Unlock() 501 if fs.open < 0 { 502 return nil, ErrClosed 503 } 504 of, err := os.OpenFile(filepath.Join(fs.path, fsGenName(fd)), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) 505 if err != nil { 506 return nil, err 507 } 508 fs.open++ 509 return &fileWrap{File: of, fs: fs, fd: fd}, nil 510 } 511 512 func (fs *fileStorage) Remove(fd FileDesc) error { 513 if !FileDescOk(fd) { 514 return ErrInvalidFile 515 } 516 if fs.readOnly { 517 return errReadOnly 518 } 519 520 fs.mu.Lock() 521 defer fs.mu.Unlock() 522 if fs.open < 0 { 523 return ErrClosed 524 } 525 err := os.Remove(filepath.Join(fs.path, fsGenName(fd))) 526 if err != nil { 527 if fsHasOldName(fd) && os.IsNotExist(err) { 528 if e1 := os.Remove(filepath.Join(fs.path, fsGenOldName(fd))); !os.IsNotExist(e1) { 529 fs.log(fmt.Sprintf("remove %s: %v (old name)", fd, err)) 530 err = e1 531 } 532 } else { 533 fs.log(fmt.Sprintf("remove %s: %v", fd, err)) 534 } 535 } 536 return err 537 } 538 539 func (fs *fileStorage) Rename(oldfd, newfd FileDesc) error { 540 if !FileDescOk(oldfd) || !FileDescOk(newfd) { 541 return ErrInvalidFile 542 } 543 if oldfd == newfd { 544 return nil 545 } 546 if fs.readOnly { 547 return errReadOnly 548 } 549 550 fs.mu.Lock() 551 defer fs.mu.Unlock() 552 if fs.open < 0 { 553 return ErrClosed 554 } 555 return rename(filepath.Join(fs.path, fsGenName(oldfd)), filepath.Join(fs.path, fsGenName(newfd))) 556 } 557 558 func (fs *fileStorage) Close() error { 559 fs.mu.Lock() 560 defer fs.mu.Unlock() 561 if fs.open < 0 { 562 return ErrClosed 563 } 564 // Clear the finalizer. 565 runtime.SetFinalizer(fs, nil) 566 567 if fs.open > 0 { 568 fs.log(fmt.Sprintf("close: warning, %d files still open", fs.open)) 569 } 570 fs.open = -1 571 if fs.logw != nil { 572 fs.logw.Close() 573 } 574 return fs.flock.release() 575 } 576 577 type fileWrap struct { 578 *os.File 579 fs *fileStorage 580 fd FileDesc 581 closed bool 582 } 583 584 func (fw *fileWrap) Sync() error { 585 if err := fw.File.Sync(); err != nil { 586 return err 587 } 588 if fw.fd.Type == TypeManifest { 589 // Also sync parent directory if file type is manifest. 590 // See: https://code.google.com/p/leveldb/issues/detail?id=190. 591 if err := syncDir(fw.fs.path); err != nil { 592 fw.fs.log(fmt.Sprintf("syncDir: %v", err)) 593 return err 594 } 595 } 596 return nil 597 } 598 599 func (fw *fileWrap) Close() error { 600 fw.fs.mu.Lock() 601 defer fw.fs.mu.Unlock() 602 if fw.closed { 603 return ErrClosed 604 } 605 fw.closed = true 606 fw.fs.open-- 607 err := fw.File.Close() 608 if err != nil { 609 fw.fs.log(fmt.Sprintf("close %s: %v", fw.fd, err)) 610 } 611 return err 612 } 613 614 func fsGenName(fd FileDesc) string { 615 switch fd.Type { 616 case TypeManifest: 617 return fmt.Sprintf("MANIFEST-%06d", fd.Num) 618 case TypeJournal: 619 return fmt.Sprintf("%06d.log", fd.Num) 620 case TypeTable: 621 return fmt.Sprintf("%06d.ldb", fd.Num) 622 case TypeTemp: 623 return fmt.Sprintf("%06d.tmp", fd.Num) 624 default: 625 panic("invalid file type") 626 } 627 } 628 629 func fsHasOldName(fd FileDesc) bool { 630 return fd.Type == TypeTable 631 } 632 633 func fsGenOldName(fd FileDesc) string { 634 switch fd.Type { 635 case TypeTable: 636 return fmt.Sprintf("%06d.sst", fd.Num) 637 } 638 return fsGenName(fd) 639 } 640 641 func fsParseName(name string) (fd FileDesc, ok bool) { 642 var tail string 643 _, err := fmt.Sscanf(name, "%d.%s", &fd.Num, &tail) 644 if err == nil { 645 switch tail { 646 case "log": 647 fd.Type = TypeJournal 648 case "ldb", "sst": 649 fd.Type = TypeTable 650 case "tmp": 651 fd.Type = TypeTemp 652 default: 653 return 654 } 655 return fd, true 656 } 657 n, _ := fmt.Sscanf(name, "MANIFEST-%d%s", &fd.Num, &tail) 658 if n == 1 { 659 fd.Type = TypeManifest 660 return fd, true 661 } 662 return 663 } 664 665 func fsParseNamePtr(name string, fd *FileDesc) bool { 666 _fd, ok := fsParseName(name) 667 if fd != nil { 668 *fd = _fd 669 } 670 return ok 671 }