EC volume supports expiration and displays expiration message when executing volume.list (#5895)
* ec volume expire * volume.list show DestroyTime * comments * code optimization --------- Co-authored-by: xuwenfeng <xuwenfeng1@zto.com>
This commit is contained in:
@@ -72,14 +72,14 @@ func (l *DiskLocation) FindEcShard(vid needle.VolumeId, shardId erasure_coding.S
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (l *DiskLocation) LoadEcShard(collection string, vid needle.VolumeId, shardId erasure_coding.ShardId) (err error) {
|
||||
func (l *DiskLocation) LoadEcShard(collection string, vid needle.VolumeId, shardId erasure_coding.ShardId) (*erasure_coding.EcVolume, error) {
|
||||
|
||||
ecVolumeShard, err := erasure_coding.NewEcVolumeShard(l.DiskType, l.Directory, collection, vid, shardId)
|
||||
if err != nil {
|
||||
if err == os.ErrNotExist {
|
||||
return os.ErrNotExist
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
return fmt.Errorf("failed to create ec shard %d.%d: %v", vid, shardId, err)
|
||||
return nil, fmt.Errorf("failed to create ec shard %d.%d: %v", vid, shardId, err)
|
||||
}
|
||||
l.ecVolumesLock.Lock()
|
||||
defer l.ecVolumesLock.Unlock()
|
||||
@@ -87,13 +87,13 @@ func (l *DiskLocation) LoadEcShard(collection string, vid needle.VolumeId, shard
|
||||
if !found {
|
||||
ecVolume, err = erasure_coding.NewEcVolume(l.DiskType, l.Directory, l.IdxDirectory, collection, vid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create ec volume %d: %v", vid, err)
|
||||
return nil, fmt.Errorf("failed to create ec volume %d: %v", vid, err)
|
||||
}
|
||||
l.ecVolumes[vid] = ecVolume
|
||||
}
|
||||
ecVolume.AddEcVolumeShard(ecVolumeShard)
|
||||
|
||||
return nil
|
||||
return ecVolume, nil
|
||||
}
|
||||
|
||||
func (l *DiskLocation) UnloadEcShard(vid needle.VolumeId, shardId erasure_coding.ShardId) bool {
|
||||
@@ -124,7 +124,7 @@ func (l *DiskLocation) loadEcShards(shards []string, collection string, vid need
|
||||
return fmt.Errorf("failed to parse ec shard name %v: %v", shard, err)
|
||||
}
|
||||
|
||||
err = l.LoadEcShard(collection, vid, erasure_coding.ShardId(shardId))
|
||||
_, err = l.LoadEcShard(collection, vid, erasure_coding.ShardId(shardId))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load ec shard %v: %v", shard, err)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package erasure_coding
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"math"
|
||||
"os"
|
||||
"sync"
|
||||
@@ -20,7 +21,8 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
NotFoundError = errors.New("needle not found")
|
||||
NotFoundError = errors.New("needle not found")
|
||||
destroyDelaySeconds int64 = 0
|
||||
)
|
||||
|
||||
type EcVolume struct {
|
||||
@@ -40,6 +42,7 @@ type EcVolume struct {
|
||||
ecjFileAccessLock sync.Mutex
|
||||
diskType types.DiskType
|
||||
datFileSize int64
|
||||
DestroyTime uint64 //ec volume destroy time, calculated from the ec volume was created
|
||||
}
|
||||
|
||||
func NewEcVolume(diskType types.DiskType, dir string, dirIdx string, collection string, vid needle.VolumeId) (ev *EcVolume, err error) {
|
||||
@@ -70,7 +73,9 @@ func NewEcVolume(diskType types.DiskType, dir string, dirIdx string, collection
|
||||
if volumeInfo, _, found, _ := volume_info.MaybeLoadVolumeInfo(dataBaseFileName + ".vif"); found {
|
||||
ev.Version = needle.Version(volumeInfo.Version)
|
||||
ev.datFileSize = volumeInfo.DatFileSize
|
||||
ev.DestroyTime = volumeInfo.DestroyTime
|
||||
} else {
|
||||
glog.Warningf("vif file not found,volumeId:%d, filename:%s", vid, dataBaseFileName)
|
||||
volume_info.SaveVolumeInfo(dataBaseFileName+".vif", &volume_server_pb.VolumeInfo{Version: uint32(ev.Version)})
|
||||
}
|
||||
|
||||
@@ -198,9 +203,10 @@ func (ev *EcVolume) ToVolumeEcShardInformationMessage() (messages []*master_pb.V
|
||||
for _, s := range ev.Shards {
|
||||
if s.VolumeId != prevVolumeId {
|
||||
m = &master_pb.VolumeEcShardInformationMessage{
|
||||
Id: uint32(s.VolumeId),
|
||||
Collection: s.Collection,
|
||||
DiskType: string(ev.diskType),
|
||||
Id: uint32(s.VolumeId),
|
||||
Collection: s.Collection,
|
||||
DiskType: string(ev.diskType),
|
||||
DestroyTime: ev.DestroyTime,
|
||||
}
|
||||
messages = append(messages, m)
|
||||
}
|
||||
@@ -269,3 +275,7 @@ func SearchNeedleFromSortedIndex(ecxFile *os.File, ecxFileSize int64, needleId t
|
||||
err = NotFoundError
|
||||
return
|
||||
}
|
||||
|
||||
func (ev *EcVolume) IsTimeToDestroy() bool {
|
||||
return ev.DestroyTime > 0 && time.Now().Unix() > (int64(ev.DestroyTime)+destroyDelaySeconds)
|
||||
}
|
||||
|
||||
@@ -7,18 +7,20 @@ import (
|
||||
|
||||
// data structure used in master
|
||||
type EcVolumeInfo struct {
|
||||
VolumeId needle.VolumeId
|
||||
Collection string
|
||||
ShardBits ShardBits
|
||||
DiskType string
|
||||
VolumeId needle.VolumeId
|
||||
Collection string
|
||||
ShardBits ShardBits
|
||||
DiskType string
|
||||
DestroyTime uint64 //ec volume destroy time, calculated from the ec volume was created
|
||||
}
|
||||
|
||||
func NewEcVolumeInfo(diskType string, collection string, vid needle.VolumeId, shardBits ShardBits) *EcVolumeInfo {
|
||||
func NewEcVolumeInfo(diskType string, collection string, vid needle.VolumeId, shardBits ShardBits, destroyTime uint64) *EcVolumeInfo {
|
||||
return &EcVolumeInfo{
|
||||
Collection: collection,
|
||||
VolumeId: vid,
|
||||
ShardBits: shardBits,
|
||||
DiskType: diskType,
|
||||
Collection: collection,
|
||||
VolumeId: vid,
|
||||
ShardBits: shardBits,
|
||||
DiskType: diskType,
|
||||
DestroyTime: destroyTime,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +61,7 @@ func (ecInfo *EcVolumeInfo) ToVolumeEcShardInformationMessage() (ret *master_pb.
|
||||
EcIndexBits: uint32(ecInfo.ShardBits),
|
||||
Collection: ecInfo.Collection,
|
||||
DiskType: ecInfo.DiskType,
|
||||
DestroyTime: ecInfo.DestroyTime,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,26 @@ func (t *TTL) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (t *TTL) ToSeconds() uint64 {
|
||||
switch t.Unit {
|
||||
case Empty:
|
||||
return 0
|
||||
case Minute:
|
||||
return uint64(t.Count) * 60
|
||||
case Hour:
|
||||
return uint64(t.Count) * 60 * 60
|
||||
case Day:
|
||||
return uint64(t.Count) * 60 * 24 * 60
|
||||
case Week:
|
||||
return uint64(t.Count) * 60 * 24 * 7 * 60
|
||||
case Month:
|
||||
return uint64(t.Count) * 60 * 24 * 30 * 60
|
||||
case Year:
|
||||
return uint64(t.Count) * 60 * 24 * 365 * 60
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func toStoredByte(readableUnitByte byte) byte {
|
||||
switch readableUnitByte {
|
||||
case 'm':
|
||||
|
||||
@@ -336,6 +336,9 @@ func (s *Store) CollectHeartbeat() *master_pb.Heartbeat {
|
||||
}
|
||||
}
|
||||
|
||||
// delete expired ec volumes
|
||||
ecVolumeMessages, deletedEcVolumes := s.deleteExpiredEcVolumes()
|
||||
|
||||
var uuidList []string
|
||||
for _, loc := range s.Locations {
|
||||
uuidList = append(uuidList, loc.DirectoryUuid)
|
||||
@@ -365,12 +368,34 @@ func (s *Store) CollectHeartbeat() *master_pb.Heartbeat {
|
||||
DataCenter: s.dataCenter,
|
||||
Rack: s.rack,
|
||||
Volumes: volumeMessages,
|
||||
DeletedEcShards: deletedEcVolumes,
|
||||
HasNoVolumes: len(volumeMessages) == 0,
|
||||
HasNoEcShards: len(ecVolumeMessages) == 0,
|
||||
LocationUuids: uuidList,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *Store) deleteExpiredEcVolumes() (ecShards, deleted []*master_pb.VolumeEcShardInformationMessage) {
|
||||
for _, location := range s.Locations {
|
||||
for _, ev := range location.ecVolumes {
|
||||
messages := ev.ToVolumeEcShardInformationMessage()
|
||||
if ev.IsTimeToDestroy() {
|
||||
err := location.deleteEcVolumeById(ev.VolumeId)
|
||||
if err != nil {
|
||||
ecShards = append(ecShards, messages...)
|
||||
glog.Errorf("delete EcVolume err %d: %v", ev.VolumeId, err)
|
||||
continue
|
||||
}
|
||||
deleted = append(deleted, messages...)
|
||||
} else {
|
||||
ecShards = append(ecShards, messages...)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Store) SetStopping() {
|
||||
s.isStopping = true
|
||||
for _, location := range s.Locations {
|
||||
|
||||
@@ -50,7 +50,7 @@ func (s *Store) CollectErasureCodingHeartbeat() *master_pb.Heartbeat {
|
||||
|
||||
func (s *Store) MountEcShards(collection string, vid needle.VolumeId, shardId erasure_coding.ShardId) error {
|
||||
for _, location := range s.Locations {
|
||||
if err := location.LoadEcShard(collection, vid, shardId); err == nil {
|
||||
if ecVolume, err := location.LoadEcShard(collection, vid, shardId); err == nil {
|
||||
glog.V(0).Infof("MountEcShards %d.%d", vid, shardId)
|
||||
|
||||
var shardBits erasure_coding.ShardBits
|
||||
@@ -60,6 +60,7 @@ func (s *Store) MountEcShards(collection string, vid needle.VolumeId, shardId er
|
||||
Collection: collection,
|
||||
EcIndexBits: uint32(shardBits.AddShardId(shardId)),
|
||||
DiskType: string(location.DiskType),
|
||||
DestroyTime: ecVolume.DestroyTime,
|
||||
}
|
||||
return nil
|
||||
} else if err == os.ErrNotExist {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/storage/needle"
|
||||
"github.com/seaweedfs/seaweedfs/weed/storage/types"
|
||||
"github.com/seaweedfs/seaweedfs/weed/storage/volume_info"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (v *Volume) GetVolumeInfo() *volume_server_pb.VolumeInfo {
|
||||
@@ -72,6 +73,12 @@ func (v *Volume) LoadRemoteFile() error {
|
||||
func (v *Volume) SaveVolumeInfo() error {
|
||||
|
||||
tierFileName := v.FileName(".vif")
|
||||
if v.Ttl != nil {
|
||||
ttlSeconds := v.Ttl.ToSeconds()
|
||||
if ttlSeconds > 0 {
|
||||
v.volumeInfo.DestroyTime = uint64(time.Now().Unix()) + ttlSeconds //calculated destroy time from the ec volume was created
|
||||
}
|
||||
}
|
||||
|
||||
return volume_info.SaveVolumeInfo(tierFileName, v.volumeInfo)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user