github.com/zuoyebang/bitalostable@v1.0.1-0.20240229032404-e3b99a834294/internal/base/filenames.go (about)

     1  // Copyright 2012 The LevelDB-Go and Pebble Authors. All rights reserved. Use
     2  // of this source code is governed by a BSD-style license that can be found in
     3  // the LICENSE file.
     4  
     5  package base
     6  
     7  import (
     8  	"fmt"
     9  	"strconv"
    10  	"strings"
    11  
    12  	"github.com/cockroachdb/errors/oserror"
    13  	"github.com/cockroachdb/redact"
    14  	"github.com/zuoyebang/bitalostable/vfs"
    15  )
    16  
    17  // FileNum is an internal DB identifier for a file.
    18  type FileNum uint64
    19  
    20  // String returns a string representation of the file number.
    21  func (fn FileNum) String() string { return fmt.Sprintf("%06d", fn) }
    22  
    23  // FileType enumerates the types of files found in a DB.
    24  type FileType int
    25  
    26  // The FileType enumeration.
    27  const (
    28  	FileTypeLog FileType = iota
    29  	FileTypeLock
    30  	FileTypeTable
    31  	FileTypeManifest
    32  	FileTypeCurrent
    33  	FileTypeOptions
    34  	FileTypeOldTemp
    35  	FileTypeTemp
    36  )
    37  
    38  // MakeFilename builds a filename from components.
    39  func MakeFilename(fileType FileType, fileNum FileNum) string {
    40  	switch fileType {
    41  	case FileTypeLog:
    42  		return fmt.Sprintf("%s.log", fileNum)
    43  	case FileTypeLock:
    44  		return "LOCK"
    45  	case FileTypeTable:
    46  		return fmt.Sprintf("%s.sst", fileNum)
    47  	case FileTypeManifest:
    48  		return fmt.Sprintf("MANIFEST-%s", fileNum)
    49  	case FileTypeCurrent:
    50  		return "CURRENT"
    51  	case FileTypeOptions:
    52  		return fmt.Sprintf("OPTIONS-%s", fileNum)
    53  	case FileTypeOldTemp:
    54  		return fmt.Sprintf("CURRENT.%s.dbtmp", fileNum)
    55  	case FileTypeTemp:
    56  		return fmt.Sprintf("temporary.%s.dbtmp", fileNum)
    57  	}
    58  	panic("unreachable")
    59  }
    60  
    61  // MakeFilepath builds a filepath from components.
    62  func MakeFilepath(fs vfs.FS, dirname string, fileType FileType, fileNum FileNum) string {
    63  	return fs.PathJoin(dirname, MakeFilename(fileType, fileNum))
    64  }
    65  
    66  // ParseFilename parses the components from a filename.
    67  func ParseFilename(fs vfs.FS, filename string) (fileType FileType, fileNum FileNum, ok bool) {
    68  	filename = fs.PathBase(filename)
    69  	switch {
    70  	case filename == "CURRENT":
    71  		return FileTypeCurrent, 0, true
    72  	case filename == "LOCK":
    73  		return FileTypeLock, 0, true
    74  	case strings.HasPrefix(filename, "MANIFEST-"):
    75  		fileNum, ok = parseFileNum(filename[len("MANIFEST-"):])
    76  		if !ok {
    77  			break
    78  		}
    79  		return FileTypeManifest, fileNum, true
    80  	case strings.HasPrefix(filename, "OPTIONS-"):
    81  		fileNum, ok = parseFileNum(filename[len("OPTIONS-"):])
    82  		if !ok {
    83  			break
    84  		}
    85  		return FileTypeOptions, fileNum, ok
    86  	case strings.HasPrefix(filename, "CURRENT.") && strings.HasSuffix(filename, ".dbtmp"):
    87  		s := strings.TrimSuffix(filename[len("CURRENT."):], ".dbtmp")
    88  		fileNum, ok = parseFileNum(s)
    89  		if !ok {
    90  			break
    91  		}
    92  		return FileTypeOldTemp, fileNum, ok
    93  	case strings.HasPrefix(filename, "temporary.") && strings.HasSuffix(filename, ".dbtmp"):
    94  		s := strings.TrimSuffix(filename[len("temporary."):], ".dbtmp")
    95  		fileNum, ok = parseFileNum(s)
    96  		if !ok {
    97  			break
    98  		}
    99  		return FileTypeTemp, fileNum, ok
   100  	default:
   101  		i := strings.IndexByte(filename, '.')
   102  		if i < 0 {
   103  			break
   104  		}
   105  		fileNum, ok = parseFileNum(filename[:i])
   106  		if !ok {
   107  			break
   108  		}
   109  		switch filename[i+1:] {
   110  		case "sst":
   111  			return FileTypeTable, fileNum, true
   112  		case "log":
   113  			return FileTypeLog, fileNum, true
   114  		}
   115  	}
   116  	return 0, fileNum, false
   117  }
   118  
   119  func parseFileNum(s string) (fileNum FileNum, ok bool) {
   120  	u, err := strconv.ParseUint(s, 10, 64)
   121  	if err != nil {
   122  		return fileNum, false
   123  	}
   124  	return FileNum(u), true
   125  }
   126  
   127  // A Fataler fatals a process with a message when called.
   128  type Fataler interface {
   129  	Fatalf(format string, args ...interface{})
   130  }
   131  
   132  // MustExist checks if err is an error indicating a file does not exist.
   133  // If it is, it lists the containing directory's files to annotate the error
   134  // with counts of the various types of files and invokes the provided fataler.
   135  // See cockroachdb/cockroach#56490.
   136  func MustExist(fs vfs.FS, filename string, fataler Fataler, err error) {
   137  	if err == nil || !oserror.IsNotExist(err) {
   138  		return
   139  	}
   140  
   141  	ls, lsErr := fs.List(fs.PathDir(filename))
   142  	if lsErr != nil {
   143  		// TODO(jackson): if oserror.IsNotExist(lsErr), the the data directory
   144  		// doesn't exist anymore. Another process likely deleted it before
   145  		// killing the process. We want to fatal the process, but without
   146  		// triggering error reporting like Sentry.
   147  		fataler.Fatalf("%s:\norig err: %s\nlist err: %s", redact.Safe(fs.PathBase(filename)), err, lsErr)
   148  	}
   149  	var total, unknown, tables, logs, manifests int
   150  	total = len(ls)
   151  	for _, f := range ls {
   152  		typ, _, ok := ParseFilename(fs, f)
   153  		if !ok {
   154  			unknown++
   155  			continue
   156  		}
   157  		switch typ {
   158  		case FileTypeTable:
   159  			tables++
   160  		case FileTypeLog:
   161  			logs++
   162  		case FileTypeManifest:
   163  			manifests++
   164  		}
   165  	}
   166  
   167  	fataler.Fatalf("%s:\n%s\ndirectory contains %d files, %d unknown, %d tables, %d logs, %d manifests",
   168  		fs.PathBase(filename), err, total, unknown, tables, logs, manifests)
   169  }