ec volume deletion is generation-aware

This commit is contained in:
chrislu
2025-08-13 01:11:37 -07:00
parent 04b141749f
commit d7d19ea9ba
4 changed files with 25 additions and 18 deletions

View File

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

View File

@@ -3285,6 +3285,7 @@ type VolumeEcShardsDeleteRequest struct {
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"`
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
sizeCache protoimpl.SizeCache
}
@@ -3340,6 +3341,13 @@ func (x *VolumeEcShardsDeleteRequest) GetShardIds() []uint32 {
return nil
}
func (x *VolumeEcShardsDeleteRequest) GetGeneration() uint32 {
if x != nil {
return x.Generation
}
return 0
}
type VolumeEcShardsDeleteResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
@@ -6538,13 +6546,16 @@ const file_volume_server_proto_rawDesc = "" +
"\n" +
"generation\x18\t \x01(\rR\n" +
"generation\"\x1c\n" +
"\x1aVolumeEcShardsCopyResponse\"w\n" +
"\x1aVolumeEcShardsCopyResponse\"\x97\x01\n" +
"\x1bVolumeEcShardsDeleteRequest\x12\x1b\n" +
"\tvolume_id\x18\x01 \x01(\rR\bvolumeId\x12\x1e\n" +
"\n" +
"collection\x18\x02 \x01(\tR\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" +
"\x1aVolumeEcShardsMountRequest\x12\x1b\n" +
"\tvolume_id\x18\x01 \x01(\rR\bvolumeId\x12\x1e\n" +

View File

@@ -258,9 +258,15 @@ func (vs *VolumeServer) VolumeEcShardsCopy(ctx context.Context, req *volume_serv
// 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) {
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 {
if err := deleteEcShardIdsForEachLocation(bName, location, req.ShardIds); err != nil {

View File

@@ -1110,29 +1110,18 @@ func (t *EcVacuumTask) deleteGenerationFilesFromNode(client volume_server_pb.Vol
VolumeId: t.volumeID,
Collection: t.collection,
ShardIds: allShardIds,
Generation: generation, // Pass generation for proper file cleanup
})
if err != nil {
// 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,
"generation": generation,
"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
return nil
}