// Open opens a LevelDB whose files live in the given directory. func Open(dirname string, opts *db.Options) (*DB, error) { d := &DB{ dirname: dirname, opts: opts, icmp: internalKeyComparer{opts.GetComparer()}, pendingOutputs: make(map[uint64]struct{}), } if opts != nil { d.icmpOpts = *opts } d.icmpOpts.Comparer = d.icmp tableCacheSize := opts.GetMaxOpenFiles() - numNonTableCacheFiles if tableCacheSize < minTableCacheSize { tableCacheSize = minTableCacheSize } // tableCache初始化 d.tableCache.init(dirname, opts.GetFileSystem(), &d.icmpOpts, tableCacheSize) // 初始化一个MemDB d.mem = memdb.New(&d.icmpOpts) // sync.Cond在Locker的基础上增加的一个消息通知的功能。 // Cond有三个方法:Wait,Signal,Broadcast。 // Wait添加一个计数,也就是添加一个阻塞的goroutine。 // Signal解除一个goroutine的阻塞,计数减一。 // Broadcast接触所有wait goroutine的阻塞。 d.compactionCond = sync.Cond{L: &d.mu} fs := opts.GetFileSystem() d.mu.Lock() defer d.mu.Unlock() // Lock the database directory. // If the directory already exists, MkdirAll does nothing and returns nil. // 如果目录已经存在,则MkdirAll啥都不干 err := fs.MkdirAll(dirname, 0755) if err != nil { return nil, err } // 创建LOCK文件,并加文件锁 fileLock, err := fs.Lock(dbFilename(dirname, fileTypeLock, 0)) if err != nil { return nil, err } defer func() { if fileLock != nil { fileLock.Close() } }() // 若CURRENT文件不存在,则调用createDB if _, err := fs.Stat(dbFilename(dirname, fileTypeCurrent, 0)); os.IsNotExist(err) { // Create the DB if it did not already exist. if err := createDB(dirname, opts); err != nil { return nil, err } } else if err != nil { return nil, fmt.Errorf("leveldb: database %q: %v", dirname, err) } else if opts.GetErrorIfDBExists() { return nil, fmt.Errorf("leveldb: database %q already exists", dirname) } // Load the version set. // 先读取CURRENT文件内容,获取manifest文件名,然后逐条记录读取manifest文件的内容,根据内容生成一个新version,放入d.versions中 err = d.versions.load(dirname, opts) if err != nil { return nil, err } // Replay any newer log files than the ones named in the manifest. var ve versionEdit ls, err := fs.List(dirname) if err != nil { return nil, err } var logFiles fileNumAndNameSlice for _, filename := range ls { ft, fn, ok := parseDBFilename(filename) if ok && ft == fileTypeLog && (fn >= d.versions.logNumber || fn == d.versions.prevLogNumber) { logFiles = append(logFiles, fileNumAndName{fn, filename}) } } sort.Sort(logFiles) for _, lf := range logFiles { // 根据日志文件重做日志中记录的操作,先将这些操作记录存入一个临时的memtable中,然后转存入磁盘上level0存储文件中 maxSeqNum, err := d.replayLogFile(&ve, fs, filepath.Join(dirname, lf.name)) if err != nil { return nil, err } d.versions.markFileNumUsed(lf.num) // 设置最新的操作序列号 if d.versions.lastSequence < maxSeqNum { d.versions.lastSequence = maxSeqNum } } // Create an empty .log file. // 创建一个新的空log文件 ve.logNumber = d.versions.nextFileNum() d.logNumber = ve.logNumber logFile, err := fs.Create(dbFilename(dirname, fileTypeLog, ve.logNumber)) if err != nil { return nil, err } defer func() { if logFile != nil { logFile.Close() } }() d.log = record.NewWriter(logFile) // Write a new manifest to disk. // 根据前面重做日志得到的ve的信息创建一个新的manifest文件 // 并在CURRENT文件中指向这个新manifest文件 if err := d.versions.logAndApply(dirname, &ve); err != nil { return nil, err } d.deleteObsoleteFiles() // 尝试调度compaction d.maybeScheduleCompaction() d.logFile, logFile = logFile, nil d.fileLock, fileLock = fileLock, nil return d, nil }
// Open opens a LevelDB whose files live in the given directory. func Open(dirname string, opts *db.Options) (*DB, error) { d := &DB{ dirname: dirname, opts: opts, icmp: internalKeyComparer{opts.GetComparer()}, pendingOutputs: make(map[uint64]struct{}), } if opts != nil { d.icmpOpts = *opts } d.icmpOpts.Comparer = d.icmp tableCacheSize := opts.GetMaxOpenFiles() - numNonTableCacheFiles if tableCacheSize < minTableCacheSize { tableCacheSize = minTableCacheSize } d.tableCache.init(dirname, opts.GetFileSystem(), &d.icmpOpts, tableCacheSize) d.mem = memdb.New(&d.icmpOpts) d.compactionCond = sync.Cond{L: &d.mu} fs := opts.GetFileSystem() d.mu.Lock() defer d.mu.Unlock() // Lock the database directory. err := fs.MkdirAll(dirname, 0755) if err != nil { return nil, err } fileLock, err := fs.Lock(dbFilename(dirname, fileTypeLock, 0)) if err != nil { return nil, err } defer func() { if fileLock != nil { fileLock.Close() } }() if _, err := fs.Stat(dbFilename(dirname, fileTypeCurrent, 0)); os.IsNotExist(err) { // Create the DB if it did not already exist. if err := createDB(dirname, opts); err != nil { return nil, err } } else if err != nil { return nil, fmt.Errorf("leveldb: database %q: %v", dirname, err) } else if opts.GetErrorIfDBExists() { return nil, fmt.Errorf("leveldb: database %q already exists", dirname) } // Load the version set. err = d.versions.load(dirname, opts) if err != nil { return nil, err } // Replay any newer log files than the ones named in the manifest. var ve versionEdit ls, err := fs.List(dirname) if err != nil { return nil, err } var logFiles fileNumAndNameSlice for _, filename := range ls { ft, fn, ok := parseDBFilename(filename) if ok && ft == fileTypeLog && (fn >= d.versions.logNumber || fn == d.versions.prevLogNumber) { logFiles = append(logFiles, fileNumAndName{fn, filename}) } } sort.Sort(logFiles) for _, lf := range logFiles { maxSeqNum, err := d.replayLogFile(&ve, fs, filepath.Join(dirname, lf.name)) if err != nil { return nil, err } d.versions.markFileNumUsed(lf.num) if d.versions.lastSequence < maxSeqNum { d.versions.lastSequence = maxSeqNum } } // Create an empty .log file. ve.logNumber = d.versions.nextFileNum() d.logNumber = ve.logNumber logFile, err := fs.Create(dbFilename(dirname, fileTypeLog, ve.logNumber)) if err != nil { return nil, err } defer func() { if logFile != nil { logFile.Close() } }() d.log = record.NewWriter(logFile) // Write a new manifest to disk. if err := d.versions.logAndApply(dirname, &ve); err != nil { return nil, err } d.deleteObsoleteFiles() d.maybeScheduleCompaction() d.logFile, logFile = logFile, nil d.fileLock, fileLock = fileLock, nil return d, nil }