You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							226 lines
						
					
					
						
							8.0 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							226 lines
						
					
					
						
							8.0 KiB
						
					
					
				
								package storage
							 | 
						|
								
							 | 
						|
								import (
							 | 
						|
									"fmt"
							 | 
						|
									"os"
							 | 
						|
								
							 | 
						|
									"github.com/seaweedfs/seaweedfs/weed/storage/types"
							 | 
						|
								
							 | 
						|
									"github.com/syndtr/goleveldb/leveldb/opt"
							 | 
						|
								
							 | 
						|
									"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"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								func loadVolumeWithoutIndex(dirname string, collection string, id needle.VolumeId, needleMapKind NeedleMapKind, ver needle.Version) (v *Volume, err error) {
							 | 
						|
									v = &Volume{dir: dirname, Collection: collection, Id: id}
							 | 
						|
									v.SuperBlock = super_block.SuperBlock{}
							 | 
						|
									v.needleMapKind = needleMapKind
							 | 
						|
									err = v.load(false, false, needleMapKind, 0, ver)
							 | 
						|
									return
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func (v *Volume) load(alsoLoadIndex bool, createDatIfMissing bool, needleMapKind NeedleMapKind, preallocate int64, ver needle.Version) (err error) {
							 | 
						|
									alreadyHasSuperBlock := false
							 | 
						|
								
							 | 
						|
									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
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
									}()
							 | 
						|
								
							 | 
						|
									hasVolumeInfoFile := v.maybeLoadVolumeInfo()
							 | 
						|
								
							 | 
						|
									if v.volumeInfo.ReadOnly && !v.HasRemoteFile() {
							 | 
						|
										// this covers the case where the volume is marked as read-only and has no remote file
							 | 
						|
										v.noWriteOrDelete = true
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if v.HasRemoteFile() {
							 | 
						|
										v.noWriteCanDelete = true
							 | 
						|
										v.noWriteOrDelete = false
							 | 
						|
										glog.V(0).Infof("loading volume %d from remote %v", v.Id, v.volumeInfo)
							 | 
						|
										if err := v.LoadRemoteFile(); err != nil {
							 | 
						|
											return fmt.Errorf("load remote file %v: %w", v.volumeInfo, err)
							 | 
						|
										}
							 | 
						|
										alreadyHasSuperBlock = true
							 | 
						|
									} else if exists, canRead, canWrite, modifiedTime, fileSize := util.CheckFile(v.FileName(".dat")); exists {
							 | 
						|
										// open dat file
							 | 
						|
										if !canRead {
							 | 
						|
											return fmt.Errorf("cannot read Volume Data file %s", v.FileName(".dat"))
							 | 
						|
										}
							 | 
						|
										var dataFile *os.File
							 | 
						|
										if canWrite {
							 | 
						|
											dataFile, err = os.OpenFile(v.FileName(".dat"), os.O_RDWR|os.O_CREATE, 0644)
							 | 
						|
										} else {
							 | 
						|
											glog.V(0).Infof("opening %s in READONLY mode", v.FileName(".dat"))
							 | 
						|
											dataFile, err = os.Open(v.FileName(".dat"))
							 | 
						|
											v.noWriteOrDelete = true
							 | 
						|
										}
							 | 
						|
										v.lastModifiedTsSeconds = uint64(modifiedTime.Unix())
							 | 
						|
										if fileSize >= super_block.SuperBlockSize {
							 | 
						|
											alreadyHasSuperBlock = true
							 | 
						|
										}
							 | 
						|
										v.DataBackend = backend.NewDiskFile(dataFile)
							 | 
						|
									} else {
							 | 
						|
										if createDatIfMissing {
							 | 
						|
											v.DataBackend, err = backend.CreateVolumeFile(v.FileName(".dat"), preallocate, v.MemoryMapMaxSizeMb)
							 | 
						|
										} else {
							 | 
						|
											return fmt.Errorf("volume data file %s does not exist", v.FileName(".dat"))
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if err != nil {
							 | 
						|
										if !os.IsPermission(err) {
							 | 
						|
											return fmt.Errorf("cannot load volume data %s: %v", v.FileName(".dat"), err)
							 | 
						|
										} else {
							 | 
						|
											return fmt.Errorf("load data file %s: %v", v.FileName(".dat"), err)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if alreadyHasSuperBlock {
							 | 
						|
										err = v.readSuperBlock()
							 | 
						|
										if err == nil {
							 | 
						|
											v.volumeInfo.Version = uint32(v.SuperBlock.Version)
							 | 
						|
										}
							 | 
						|
										glog.V(0).Infof("readSuperBlock volume %d version %v", v.Id, v.SuperBlock.Version)
							 | 
						|
										if v.HasRemoteFile() {
							 | 
						|
											// maybe temporary network problem
							 | 
						|
											glog.Errorf("readSuperBlock remote volume %d: %v", v.Id, err)
							 | 
						|
											err = nil
							 | 
						|
										}
							 | 
						|
									} else {
							 | 
						|
										if !v.SuperBlock.Initialized() {
							 | 
						|
											return fmt.Errorf("volume %s not initialized", v.FileName(".dat"))
							 | 
						|
										}
							 | 
						|
										err = v.maybeWriteSuperBlock(ver)
							 | 
						|
									}
							 | 
						|
									if err == nil && alsoLoadIndex {
							 | 
						|
										// adjust for existing volumes with .idx together with .dat files
							 | 
						|
										if v.dirIdx != v.dir {
							 | 
						|
											if util.FileExists(v.DataFileName() + ".idx") {
							 | 
						|
												v.dirIdx = v.dir
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
										// check volume idx files
							 | 
						|
										if err := v.checkIdxFile(); err != nil {
							 | 
						|
											glog.Fatalf("check volume idx file %s: %v", v.FileName(".idx"), err)
							 | 
						|
										}
							 | 
						|
										var indexFile *os.File
							 | 
						|
										if v.noWriteOrDelete {
							 | 
						|
											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 {
							 | 
						|
												return fmt.Errorf("cannot read Volume Index %s: %v", v.FileName(".idx"), err)
							 | 
						|
											}
							 | 
						|
										} else {
							 | 
						|
											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 {
							 | 
						|
												return fmt.Errorf("cannot write Volume Index %s: %v", v.FileName(".idx"), err)
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
										// Do not need to check the data integrity for remote volumes,
							 | 
						|
										// since the remote storage tier may have larger capacity, the volume
							 | 
						|
										// data read will trigger the ReadAt() function to read from the remote
							 | 
						|
										// storage tier, and download to local storage, which may cause the
							 | 
						|
										// capactiy overloading.
							 | 
						|
										if !v.HasRemoteFile() {
							 | 
						|
											glog.V(0).Infof("checking volume data integrity for volume %d", v.Id)
							 | 
						|
											if v.lastAppendAtNs, err = CheckVolumeDataIntegrity(v, indexFile); err != nil {
							 | 
						|
												v.noWriteOrDelete = true
							 | 
						|
												glog.V(0).Infof("volumeDataIntegrityChecking failed %v", err)
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										if v.noWriteOrDelete || v.noWriteCanDelete {
							 | 
						|
											if v.nm, err = NewSortedFileNeedleMap(v.IndexFileName(), indexFile); err != nil {
							 | 
						|
												glog.V(0).Infof("loading sorted db %s error: %v", v.FileName(".sdx"), err)
							 | 
						|
											}
							 | 
						|
										} else {
							 | 
						|
											switch needleMapKind {
							 | 
						|
											case NeedleMapInMemory:
							 | 
						|
												if v.tmpNm != nil {
							 | 
						|
													glog.V(0).Infof("updating memory compact index %s ", v.FileName(".idx"))
							 | 
						|
													err = v.tmpNm.UpdateNeedleMap(v, indexFile, nil, 0)
							 | 
						|
												} else {
							 | 
						|
													glog.V(0).Infoln("loading memory index", v.FileName(".idx"), "to memory")
							 | 
						|
													if v.nm, err = LoadCompactNeedleMap(indexFile); err != nil {
							 | 
						|
														glog.V(0).Infof("loading index %s to memory error: %v", v.FileName(".idx"), err)
							 | 
						|
													}
							 | 
						|
												}
							 | 
						|
											case NeedleMapLevelDb:
							 | 
						|
												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
							 | 
						|
												}
							 | 
						|
												if v.tmpNm != nil {
							 | 
						|
													glog.V(0).Infoln("updating leveldb index", v.FileName(".ldb"))
							 | 
						|
													err = v.tmpNm.UpdateNeedleMap(v, indexFile, opts, v.ldbTimeout)
							 | 
						|
												} else {
							 | 
						|
													glog.V(0).Infoln("loading leveldb index", v.FileName(".ldb"))
							 | 
						|
													if v.nm, err = NewLevelDbNeedleMap(v.FileName(".ldb"), indexFile, opts, v.ldbTimeout); err != nil {
							 | 
						|
														glog.V(0).Infof("loading leveldb %s error: %v", v.FileName(".ldb"), err)
							 | 
						|
													}
							 | 
						|
												}
							 | 
						|
											case NeedleMapLevelDbMedium:
							 | 
						|
												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
							 | 
						|
												}
							 | 
						|
												if v.tmpNm != nil {
							 | 
						|
													glog.V(0).Infoln("updating leveldb medium index", v.FileName(".ldb"))
							 | 
						|
													err = v.tmpNm.UpdateNeedleMap(v, indexFile, opts, v.ldbTimeout)
							 | 
						|
												} else {
							 | 
						|
													glog.V(0).Infoln("loading leveldb medium index", v.FileName(".ldb"))
							 | 
						|
													if v.nm, err = NewLevelDbNeedleMap(v.FileName(".ldb"), indexFile, opts, v.ldbTimeout); err != nil {
							 | 
						|
														glog.V(0).Infof("loading leveldb %s error: %v", v.FileName(".ldb"), err)
							 | 
						|
													}
							 | 
						|
												}
							 | 
						|
											case NeedleMapLevelDbLarge:
							 | 
						|
												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
							 | 
						|
												}
							 | 
						|
												if v.tmpNm != nil {
							 | 
						|
													glog.V(0).Infoln("updating leveldb large index", v.FileName(".ldb"))
							 | 
						|
													err = v.tmpNm.UpdateNeedleMap(v, indexFile, opts, v.ldbTimeout)
							 | 
						|
												} else {
							 | 
						|
													glog.V(0).Infoln("loading leveldb large index", v.FileName(".ldb"))
							 | 
						|
													if v.nm, err = NewLevelDbNeedleMap(v.FileName(".ldb"), indexFile, opts, v.ldbTimeout); err != nil {
							 | 
						|
														glog.V(0).Infof("loading leveldb %s error: %v", v.FileName(".ldb"), err)
							 | 
						|
													}
							 | 
						|
												}
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if !hasVolumeInfoFile {
							 | 
						|
										v.volumeInfo.Version = uint32(v.SuperBlock.Version)
							 | 
						|
										v.volumeInfo.BytesOffset = uint32(types.OffsetSize)
							 | 
						|
										if err := v.SaveVolumeInfo(); err != nil {
							 | 
						|
											glog.Warningf("volume %d failed to save file info: %v", v.Id, err)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									stats.VolumeServerVolumeGauge.WithLabelValues(v.Collection, "volume").Inc()
							 | 
						|
								
							 | 
						|
									if err == nil {
							 | 
						|
										hasLoadedVolume = true
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									return err
							 | 
						|
								}
							 |