Browse Source

ec volume deletion is generation-aware

add-ec-vacuum
chrislu 4 months ago
parent
commit
d7d19ea9ba
  1. 1
      weed/pb/volume_server.proto
  2. 15
      weed/pb/volume_server_pb/volume_server.pb.go
  3. 10
      weed/server/volume_grpc_erasure_coding.go
  4. 17
      weed/worker/tasks/ec_vacuum/ec_vacuum_task.go

1
weed/pb/volume_server.proto

@ -417,6 +417,7 @@ message VolumeEcShardsDeleteRequest {
uint32 volume_id = 1; uint32 volume_id = 1;
string collection = 2; string collection = 2;
repeated uint32 shard_ids = 3; repeated uint32 shard_ids = 3;
uint32 generation = 4; // Generation support for EC vacuum cleanup
} }
message VolumeEcShardsDeleteResponse { message VolumeEcShardsDeleteResponse {
} }

15
weed/pb/volume_server_pb/volume_server.pb.go

@ -3285,6 +3285,7 @@ type VolumeEcShardsDeleteRequest struct {
VolumeId uint32 `protobuf:"varint,1,opt,name=volume_id,json=volumeId,proto3" json:"volume_id,omitempty"` VolumeId uint32 `protobuf:"varint,1,opt,name=volume_id,json=volumeId,proto3" json:"volume_id,omitempty"`
Collection string `protobuf:"bytes,2,opt,name=collection,proto3" json:"collection,omitempty"` Collection string `protobuf:"bytes,2,opt,name=collection,proto3" json:"collection,omitempty"`
ShardIds []uint32 `protobuf:"varint,3,rep,packed,name=shard_ids,json=shardIds,proto3" json:"shard_ids,omitempty"` ShardIds []uint32 `protobuf:"varint,3,rep,packed,name=shard_ids,json=shardIds,proto3" json:"shard_ids,omitempty"`
Generation uint32 `protobuf:"varint,4,opt,name=generation,proto3" json:"generation,omitempty"` // Generation support for EC vacuum cleanup
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -3340,6 +3341,13 @@ func (x *VolumeEcShardsDeleteRequest) GetShardIds() []uint32 {
return nil return nil
} }
func (x *VolumeEcShardsDeleteRequest) GetGeneration() uint32 {
if x != nil {
return x.Generation
}
return 0
}
type VolumeEcShardsDeleteResponse struct { type VolumeEcShardsDeleteResponse struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
@ -6538,13 +6546,16 @@ const file_volume_server_proto_rawDesc = "" +
"\n" + "\n" +
"generation\x18\t \x01(\rR\n" + "generation\x18\t \x01(\rR\n" +
"generation\"\x1c\n" + "generation\"\x1c\n" +
"\x1aVolumeEcShardsCopyResponse\"w\n" +
"\x1aVolumeEcShardsCopyResponse\"\x97\x01\n" +
"\x1bVolumeEcShardsDeleteRequest\x12\x1b\n" + "\x1bVolumeEcShardsDeleteRequest\x12\x1b\n" +
"\tvolume_id\x18\x01 \x01(\rR\bvolumeId\x12\x1e\n" + "\tvolume_id\x18\x01 \x01(\rR\bvolumeId\x12\x1e\n" +
"\n" + "\n" +
"collection\x18\x02 \x01(\tR\n" + "collection\x18\x02 \x01(\tR\n" +
"collection\x12\x1b\n" + "collection\x12\x1b\n" +
"\tshard_ids\x18\x03 \x03(\rR\bshardIds\"\x1e\n" +
"\tshard_ids\x18\x03 \x03(\rR\bshardIds\x12\x1e\n" +
"\n" +
"generation\x18\x04 \x01(\rR\n" +
"generation\"\x1e\n" +
"\x1cVolumeEcShardsDeleteResponse\"\x96\x01\n" + "\x1cVolumeEcShardsDeleteResponse\"\x96\x01\n" +
"\x1aVolumeEcShardsMountRequest\x12\x1b\n" + "\x1aVolumeEcShardsMountRequest\x12\x1b\n" +
"\tvolume_id\x18\x01 \x01(\rR\bvolumeId\x12\x1e\n" + "\tvolume_id\x18\x01 \x01(\rR\bvolumeId\x12\x1e\n" +

10
weed/server/volume_grpc_erasure_coding.go

@ -258,9 +258,15 @@ func (vs *VolumeServer) VolumeEcShardsCopy(ctx context.Context, req *volume_serv
// the shard should not be mounted before calling this. // the shard should not be mounted before calling this.
func (vs *VolumeServer) VolumeEcShardsDelete(ctx context.Context, req *volume_server_pb.VolumeEcShardsDeleteRequest) (*volume_server_pb.VolumeEcShardsDeleteResponse, error) { func (vs *VolumeServer) VolumeEcShardsDelete(ctx context.Context, req *volume_server_pb.VolumeEcShardsDeleteRequest) (*volume_server_pb.VolumeEcShardsDeleteResponse, error) {
bName := erasure_coding.EcShardBaseFileName(req.Collection, int(req.VolumeId))
// Use generation-aware base filename if generation is specified
var bName string
if req.Generation > 0 {
bName = erasure_coding.EcShardBaseFileNameWithGeneration(req.Collection, int(req.VolumeId), req.Generation)
} else {
bName = erasure_coding.EcShardBaseFileName(req.Collection, int(req.VolumeId))
}
glog.V(0).Infof("ec volume %s shard delete %v", bName, req.ShardIds)
glog.V(0).Infof("ec volume %s shard delete %v generation %d", bName, req.ShardIds, req.Generation)
for _, location := range vs.store.Locations { for _, location := range vs.store.Locations {
if err := deleteEcShardIdsForEachLocation(bName, location, req.ShardIds); err != nil { if err := deleteEcShardIdsForEachLocation(bName, location, req.ShardIds); err != nil {

17
weed/worker/tasks/ec_vacuum/ec_vacuum_task.go

@ -1110,29 +1110,18 @@ func (t *EcVacuumTask) deleteGenerationFilesFromNode(client volume_server_pb.Vol
VolumeId: t.volumeID, VolumeId: t.volumeID,
Collection: t.collection, Collection: t.collection,
ShardIds: allShardIds, ShardIds: allShardIds,
Generation: generation, // Pass generation for proper file cleanup
}) })
if err != nil { if err != nil {
// Log warning but don't fail - the unmount should have made files safe for cleanup // Log warning but don't fail - the unmount should have made files safe for cleanup
t.LogWarning("VolumeEcShardsDelete returned error - this is expected for generation > 0", map[string]interface{}{
t.LogWarning("VolumeEcShardsDelete returned error", map[string]interface{}{
"volume_id": t.volumeID, "volume_id": t.volumeID,
"generation": generation, "generation": generation,
"error": err.Error(), "error": err.Error(),
"note": "Generation > 0 files need manual cleanup or volume server extension",
"note": "File deletion failed but files were unmounted",
}) })
// For generation > 0, the files are unmounted but not deleted
// This is a known limitation - the volume server would need to be extended
// to support generation-aware file deletion in VolumeEcShardsDelete
if generation > 0 {
t.LogInfo("Generation > 0 file cleanup limitation", map[string]interface{}{
"volume_id": t.volumeID,
"generation": generation,
"status": "unmounted_but_not_deleted",
"note": "Files are unmounted from memory but remain on disk until manual cleanup",
})
}
// Don't return error - unmounting is the primary safety requirement // Don't return error - unmounting is the primary safety requirement
return nil return nil
} }

Loading…
Cancel
Save