2016-07-02 23:56:49 -07:00
|
|
|
package storage
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
|
2019-04-18 21:43:36 -07:00
|
|
|
"github.com/syndtr/goleveldb/leveldb/opt"
|
|
|
|
|
2022-07-29 00:17:28 -07:00
|
|
|
"github.com/seaweedfs/seaweedfs/weed/glog"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/stats"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/backend"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/needle"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/super_block"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/util"
|
2016-07-02 23:56:49 -07:00
|
|
|
)
|
|
|
|
|
2021-02-07 09:00:03 +08:00
|
|
|
func loadVolumeWithoutIndex(dirname string, collection string, id needle.VolumeId, needleMapKind NeedleMapKind) (v *Volume, err error) {
|
2016-07-02 23:56:49 -07:00
|
|
|
v = &Volume{dir: dirname, Collection: collection, Id: id}
|
2019-12-23 12:48:20 -08:00
|
|
|
v.SuperBlock = super_block.SuperBlock{}
|
2016-07-02 23:56:49 -07:00
|
|
|
v.needleMapKind = needleMapKind
|
2019-12-19 00:44:46 -08:00
|
|
|
err = v.load(false, false, needleMapKind, 0)
|
2016-07-02 23:56:49 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-02-07 09:00:03 +08:00
|
|
|
func (v *Volume) load(alsoLoadIndex bool, createDatIfMissing bool, needleMapKind NeedleMapKind, preallocate int64) (err error) {
|
2018-09-09 02:48:58 -07:00
|
|
|
alreadyHasSuperBlock := false
|
2016-07-02 23:56:49 -07:00
|
|
|
|
2020-12-04 21:50:26 -08:00
|
|
|
hasLoadedVolume := false
|
|
|
|
defer func() {
|
|
|
|
if !hasLoadedVolume {
|
|
|
|
if v.nm != nil {
|
|
|
|
v.nm.Close()
|
|
|
|
v.nm = nil
|
|
|
|
}
|
|
|
|
if v.DataBackend != nil {
|
|
|
|
v.DataBackend.Close()
|
|
|
|
v.DataBackend = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2021-03-01 00:48:30 -08:00
|
|
|
hasVolumeInfoFile := v.maybeLoadVolumeInfo()
|
2019-12-28 11:35:27 -08:00
|
|
|
|
|
|
|
if v.HasRemoteFile() {
|
2019-12-19 00:42:46 -08:00
|
|
|
v.noWriteCanDelete = true
|
2019-12-28 11:35:27 -08:00
|
|
|
v.noWriteOrDelete = false
|
2021-03-01 00:48:30 -08:00
|
|
|
glog.V(0).Infof("loading volume %d from remote %v", v.Id, v.volumeInfo)
|
2019-12-28 11:35:27 -08:00
|
|
|
v.LoadRemoteFile()
|
2019-12-02 15:08:28 -08:00
|
|
|
alreadyHasSuperBlock = true
|
2020-11-27 03:17:10 -08:00
|
|
|
} else if exists, canRead, canWrite, modifiedTime, fileSize := util.CheckFile(v.FileName(".dat")); exists {
|
2019-12-02 15:08:28 -08:00
|
|
|
// open dat file
|
2016-07-02 23:56:49 -07:00
|
|
|
if !canRead {
|
2020-11-27 03:17:10 -08:00
|
|
|
return fmt.Errorf("cannot read Volume Data file %s", v.FileName(".dat"))
|
2016-07-02 23:56:49 -07:00
|
|
|
}
|
2019-11-09 00:10:59 -08:00
|
|
|
var dataFile *os.File
|
2016-07-02 23:56:49 -07:00
|
|
|
if canWrite {
|
2020-11-27 03:17:10 -08:00
|
|
|
dataFile, err = os.OpenFile(v.FileName(".dat"), os.O_RDWR|os.O_CREATE, 0644)
|
2016-07-02 23:56:49 -07:00
|
|
|
} else {
|
2020-11-27 03:17:10 -08:00
|
|
|
glog.V(0).Infof("opening %s in READONLY mode", v.FileName(".dat"))
|
|
|
|
dataFile, err = os.Open(v.FileName(".dat"))
|
2019-12-19 00:42:46 -08:00
|
|
|
v.noWriteOrDelete = true
|
2016-07-02 23:56:49 -07:00
|
|
|
}
|
2019-08-21 11:26:01 +08:00
|
|
|
v.lastModifiedTsSeconds = uint64(modifiedTime.Unix())
|
2019-12-23 12:48:20 -08:00
|
|
|
if fileSize >= super_block.SuperBlockSize {
|
2018-09-09 02:48:58 -07:00
|
|
|
alreadyHasSuperBlock = true
|
|
|
|
}
|
2019-11-09 00:10:59 -08:00
|
|
|
v.DataBackend = backend.NewDiskFile(dataFile)
|
2016-07-02 23:56:49 -07:00
|
|
|
} else {
|
|
|
|
if createDatIfMissing {
|
2020-11-27 03:17:10 -08:00
|
|
|
v.DataBackend, err = backend.CreateVolumeFile(v.FileName(".dat"), preallocate, v.MemoryMapMaxSizeMb)
|
2016-07-02 23:56:49 -07:00
|
|
|
} else {
|
2020-11-27 03:17:10 -08:00
|
|
|
return fmt.Errorf("volume data file %s does not exist", v.FileName(".dat"))
|
2016-07-02 23:56:49 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-19 00:44:46 -08:00
|
|
|
if err != nil {
|
|
|
|
if !os.IsPermission(err) {
|
2020-11-27 03:17:10 -08:00
|
|
|
return fmt.Errorf("cannot load volume data %s: %v", v.FileName(".dat"), err)
|
2018-07-09 23:31:25 -07:00
|
|
|
} else {
|
2020-11-27 03:17:10 -08:00
|
|
|
return fmt.Errorf("load data file %s: %v", v.FileName(".dat"), err)
|
2016-07-02 23:56:49 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-09 02:48:58 -07:00
|
|
|
if alreadyHasSuperBlock {
|
2019-12-19 00:44:46 -08:00
|
|
|
err = v.readSuperBlock()
|
2021-12-05 01:06:01 -08:00
|
|
|
if err == nil {
|
|
|
|
v.volumeInfo.Version = uint32(v.SuperBlock.Version)
|
|
|
|
}
|
2021-03-01 00:48:59 -08:00
|
|
|
glog.V(0).Infof("readSuperBlock volume %d version %v", v.Id, v.SuperBlock.Version)
|
2021-03-01 01:20:06 -08:00
|
|
|
if v.HasRemoteFile() {
|
|
|
|
// maybe temporary network problem
|
|
|
|
glog.Errorf("readSuperBlock remote volume %d: %v", v.Id, err)
|
|
|
|
err = nil
|
|
|
|
}
|
2016-07-02 23:56:49 -07:00
|
|
|
} else {
|
2019-10-09 00:02:50 -07:00
|
|
|
if !v.SuperBlock.Initialized() {
|
2020-11-27 03:17:10 -08:00
|
|
|
return fmt.Errorf("volume %s not initialized", v.FileName(".dat"))
|
2019-10-09 00:02:50 -07:00
|
|
|
}
|
2019-12-19 00:44:46 -08:00
|
|
|
err = v.maybeWriteSuperBlock()
|
2016-07-02 23:56:49 -07:00
|
|
|
}
|
2019-12-19 00:44:46 -08:00
|
|
|
if err == nil && alsoLoadIndex {
|
2020-11-27 03:17:10 -08:00
|
|
|
// adjust for existing volumes with .idx together with .dat files
|
|
|
|
if v.dirIdx != v.dir {
|
2020-12-22 02:34:08 -08:00
|
|
|
if util.FileExists(v.DataFileName() + ".idx") {
|
2020-11-27 03:17:10 -08:00
|
|
|
v.dirIdx = v.dir
|
|
|
|
}
|
|
|
|
}
|
2021-02-11 00:44:40 -08:00
|
|
|
// check volume idx files
|
|
|
|
if err := v.checkIdxFile(); err != nil {
|
|
|
|
glog.Fatalf("check volume idx file %s: %v", v.FileName(".idx"), err)
|
|
|
|
}
|
2016-07-02 23:56:49 -07:00
|
|
|
var indexFile *os.File
|
2019-12-19 00:42:46 -08:00
|
|
|
if v.noWriteOrDelete {
|
2020-11-27 03:17:10 -08:00
|
|
|
glog.V(0).Infoln("open to read file", v.FileName(".idx"))
|
|
|
|
if indexFile, err = os.OpenFile(v.FileName(".idx"), os.O_RDONLY, 0644); err != nil {
|
2020-12-22 02:34:08 -08:00
|
|
|
return fmt.Errorf("cannot read Volume Index %s: %v", v.FileName(".idx"), err)
|
2016-07-02 23:56:49 -07:00
|
|
|
}
|
|
|
|
} else {
|
2020-11-27 03:17:10 -08:00
|
|
|
glog.V(1).Infoln("open to write file", v.FileName(".idx"))
|
|
|
|
if indexFile, err = os.OpenFile(v.FileName(".idx"), os.O_RDWR|os.O_CREATE, 0644); err != nil {
|
2020-12-22 02:34:08 -08:00
|
|
|
return fmt.Errorf("cannot write Volume Index %s: %v", v.FileName(".idx"), err)
|
2016-07-02 23:56:49 -07:00
|
|
|
}
|
|
|
|
}
|
2020-10-28 01:14:39 -07:00
|
|
|
if v.lastAppendAtNs, err = CheckAndFixVolumeDataIntegrity(v, indexFile); err != nil {
|
2019-12-19 00:42:46 -08:00
|
|
|
v.noWriteOrDelete = true
|
2019-12-19 00:44:46 -08:00
|
|
|
glog.V(0).Infof("volumeDataIntegrityChecking failed %v", err)
|
2016-07-02 23:56:49 -07:00
|
|
|
}
|
2019-12-18 01:21:21 -08:00
|
|
|
|
2020-07-03 16:34:31 -07:00
|
|
|
if v.noWriteOrDelete || v.noWriteCanDelete {
|
2020-11-27 03:17:10 -08:00
|
|
|
if v.nm, err = NewSortedFileNeedleMap(v.IndexFileName(), indexFile); err != nil {
|
2020-12-22 02:34:08 -08:00
|
|
|
glog.V(0).Infof("loading sorted db %s error: %v", v.FileName(".sdx"), err)
|
2019-04-09 09:42:06 -07:00
|
|
|
}
|
2019-12-18 01:21:21 -08:00
|
|
|
} else {
|
|
|
|
switch needleMapKind {
|
|
|
|
case NeedleMapInMemory:
|
2020-11-27 03:17:10 -08:00
|
|
|
glog.V(0).Infoln("loading index", v.FileName(".idx"), "to memory")
|
2019-12-19 00:44:46 -08:00
|
|
|
if v.nm, err = LoadCompactNeedleMap(indexFile); err != nil {
|
2020-11-27 03:17:10 -08:00
|
|
|
glog.V(0).Infof("loading index %s to memory error: %v", v.FileName(".idx"), err)
|
2019-12-18 01:21:21 -08:00
|
|
|
}
|
|
|
|
case NeedleMapLevelDb:
|
2020-11-27 03:17:10 -08:00
|
|
|
glog.V(0).Infoln("loading leveldb", v.FileName(".ldb"))
|
2019-12-18 01:21:21 -08:00
|
|
|
opts := &opt.Options{
|
|
|
|
BlockCacheCapacity: 2 * 1024 * 1024, // default value is 8MiB
|
|
|
|
WriteBuffer: 1 * 1024 * 1024, // default value is 4MiB
|
|
|
|
CompactionTableSizeMultiplier: 10, // default value is 1
|
|
|
|
}
|
2020-11-27 03:17:10 -08:00
|
|
|
if v.nm, err = NewLevelDbNeedleMap(v.FileName(".ldb"), indexFile, opts); err != nil {
|
|
|
|
glog.V(0).Infof("loading leveldb %s error: %v", v.FileName(".ldb"), err)
|
2019-12-18 01:21:21 -08:00
|
|
|
}
|
|
|
|
case NeedleMapLevelDbMedium:
|
2020-11-27 03:17:10 -08:00
|
|
|
glog.V(0).Infoln("loading leveldb medium", v.FileName(".ldb"))
|
2019-12-18 01:21:21 -08:00
|
|
|
opts := &opt.Options{
|
|
|
|
BlockCacheCapacity: 4 * 1024 * 1024, // default value is 8MiB
|
|
|
|
WriteBuffer: 2 * 1024 * 1024, // default value is 4MiB
|
|
|
|
CompactionTableSizeMultiplier: 10, // default value is 1
|
|
|
|
}
|
2020-11-27 03:17:10 -08:00
|
|
|
if v.nm, err = NewLevelDbNeedleMap(v.FileName(".ldb"), indexFile, opts); err != nil {
|
|
|
|
glog.V(0).Infof("loading leveldb %s error: %v", v.FileName(".ldb"), err)
|
2019-12-18 01:21:21 -08:00
|
|
|
}
|
|
|
|
case NeedleMapLevelDbLarge:
|
2020-11-27 03:17:10 -08:00
|
|
|
glog.V(0).Infoln("loading leveldb large", v.FileName(".ldb"))
|
2019-12-18 01:21:21 -08:00
|
|
|
opts := &opt.Options{
|
|
|
|
BlockCacheCapacity: 8 * 1024 * 1024, // default value is 8MiB
|
|
|
|
WriteBuffer: 4 * 1024 * 1024, // default value is 4MiB
|
|
|
|
CompactionTableSizeMultiplier: 10, // default value is 1
|
|
|
|
}
|
2020-11-27 03:17:10 -08:00
|
|
|
if v.nm, err = NewLevelDbNeedleMap(v.FileName(".ldb"), indexFile, opts); err != nil {
|
|
|
|
glog.V(0).Infof("loading leveldb %s error: %v", v.FileName(".ldb"), err)
|
2019-12-18 01:21:21 -08:00
|
|
|
}
|
2017-05-26 22:51:25 -07:00
|
|
|
}
|
2016-07-02 23:56:49 -07:00
|
|
|
}
|
|
|
|
}
|
2017-01-06 10:22:20 -08:00
|
|
|
|
2020-01-08 09:45:26 -08:00
|
|
|
if !hasVolumeInfoFile {
|
|
|
|
v.volumeInfo.Version = uint32(v.SuperBlock.Version)
|
|
|
|
v.SaveVolumeInfo()
|
|
|
|
}
|
|
|
|
|
2019-06-17 21:02:50 -07:00
|
|
|
stats.VolumeServerVolumeCounter.WithLabelValues(v.Collection, "volume").Inc()
|
2019-06-16 02:24:15 -07:00
|
|
|
|
2020-12-04 21:50:26 -08:00
|
|
|
if err == nil {
|
|
|
|
hasLoadedVolume = true
|
|
|
|
}
|
|
|
|
|
2019-12-19 00:44:46 -08:00
|
|
|
return err
|
2016-07-02 23:56:49 -07:00
|
|
|
}
|