diff --git a/weed/pb/volume_server.proto b/weed/pb/volume_server.proto index b5ebe6bed..78d19b285 100644 --- a/weed/pb/volume_server.proto +++ b/weed/pb/volume_server.proto @@ -47,6 +47,13 @@ service VolumeServer { rpc VolumeTailReceiver (VolumeTailReceiverRequest) returns (VolumeTailReceiverResponse) { } + // erasure coding + rpc VolumeEcGenerateSlices (VolumeEcGenerateSlicesRequest) returns (VolumeEcGenerateSlicesResponse) { + } + rpc VolumeEcCopy (VolumeEcCopyRequest) returns (VolumeEcCopyResponse) { + } + + } ////////////////////////////////////////////////// @@ -190,6 +197,21 @@ message VolumeTailReceiverRequest { message VolumeTailReceiverResponse { } +message VolumeEcGenerateSlicesRequest { + uint32 volume_id = 1; +} +message VolumeEcGenerateSlicesResponse { +} + +message VolumeEcCopyRequest { + uint32 volume_id = 1; + string collection = 2; + repeated uint32 ec_indexes = 3; + string source_data_node = 5; +} +message VolumeEcCopyResponse { +} + message ReadVolumeFileStatusRequest { uint32 volume_id = 1; } diff --git a/weed/pb/volume_server_pb/volume_server.pb.go b/weed/pb/volume_server_pb/volume_server.pb.go index 10bebc65e..e30e76947 100644 --- a/weed/pb/volume_server_pb/volume_server.pb.go +++ b/weed/pb/volume_server_pb/volume_server.pb.go @@ -43,6 +43,10 @@ It has these top-level messages: VolumeTailSenderResponse VolumeTailReceiverRequest VolumeTailReceiverResponse + VolumeEcGenerateSlicesRequest + VolumeEcGenerateSlicesResponse + VolumeEcCopyRequest + VolumeEcCopyResponse ReadVolumeFileStatusRequest ReadVolumeFileStatusResponse DiskStatus @@ -766,6 +770,78 @@ func (m *VolumeTailReceiverResponse) String() string { return proto.C func (*VolumeTailReceiverResponse) ProtoMessage() {} func (*VolumeTailReceiverResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{33} } +type VolumeEcGenerateSlicesRequest struct { + VolumeId uint32 `protobuf:"varint,1,opt,name=volume_id,json=volumeId" json:"volume_id,omitempty"` +} + +func (m *VolumeEcGenerateSlicesRequest) Reset() { *m = VolumeEcGenerateSlicesRequest{} } +func (m *VolumeEcGenerateSlicesRequest) String() string { return proto.CompactTextString(m) } +func (*VolumeEcGenerateSlicesRequest) ProtoMessage() {} +func (*VolumeEcGenerateSlicesRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{34} } + +func (m *VolumeEcGenerateSlicesRequest) GetVolumeId() uint32 { + if m != nil { + return m.VolumeId + } + return 0 +} + +type VolumeEcGenerateSlicesResponse struct { +} + +func (m *VolumeEcGenerateSlicesResponse) Reset() { *m = VolumeEcGenerateSlicesResponse{} } +func (m *VolumeEcGenerateSlicesResponse) String() string { return proto.CompactTextString(m) } +func (*VolumeEcGenerateSlicesResponse) ProtoMessage() {} +func (*VolumeEcGenerateSlicesResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{35} } + +type VolumeEcCopyRequest struct { + VolumeId uint32 `protobuf:"varint,1,opt,name=volume_id,json=volumeId" json:"volume_id,omitempty"` + Collection string `protobuf:"bytes,2,opt,name=collection" json:"collection,omitempty"` + EcIndexes []uint32 `protobuf:"varint,3,rep,packed,name=ec_indexes,json=ecIndexes" json:"ec_indexes,omitempty"` + SourceDataNode string `protobuf:"bytes,5,opt,name=source_data_node,json=sourceDataNode" json:"source_data_node,omitempty"` +} + +func (m *VolumeEcCopyRequest) Reset() { *m = VolumeEcCopyRequest{} } +func (m *VolumeEcCopyRequest) String() string { return proto.CompactTextString(m) } +func (*VolumeEcCopyRequest) ProtoMessage() {} +func (*VolumeEcCopyRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{36} } + +func (m *VolumeEcCopyRequest) GetVolumeId() uint32 { + if m != nil { + return m.VolumeId + } + return 0 +} + +func (m *VolumeEcCopyRequest) GetCollection() string { + if m != nil { + return m.Collection + } + return "" +} + +func (m *VolumeEcCopyRequest) GetEcIndexes() []uint32 { + if m != nil { + return m.EcIndexes + } + return nil +} + +func (m *VolumeEcCopyRequest) GetSourceDataNode() string { + if m != nil { + return m.SourceDataNode + } + return "" +} + +type VolumeEcCopyResponse struct { +} + +func (m *VolumeEcCopyResponse) Reset() { *m = VolumeEcCopyResponse{} } +func (m *VolumeEcCopyResponse) String() string { return proto.CompactTextString(m) } +func (*VolumeEcCopyResponse) ProtoMessage() {} +func (*VolumeEcCopyResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{37} } + type ReadVolumeFileStatusRequest struct { VolumeId uint32 `protobuf:"varint,1,opt,name=volume_id,json=volumeId" json:"volume_id,omitempty"` } @@ -773,7 +849,7 @@ type ReadVolumeFileStatusRequest struct { func (m *ReadVolumeFileStatusRequest) Reset() { *m = ReadVolumeFileStatusRequest{} } func (m *ReadVolumeFileStatusRequest) String() string { return proto.CompactTextString(m) } func (*ReadVolumeFileStatusRequest) ProtoMessage() {} -func (*ReadVolumeFileStatusRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{34} } +func (*ReadVolumeFileStatusRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{38} } func (m *ReadVolumeFileStatusRequest) GetVolumeId() uint32 { if m != nil { @@ -796,7 +872,7 @@ type ReadVolumeFileStatusResponse struct { func (m *ReadVolumeFileStatusResponse) Reset() { *m = ReadVolumeFileStatusResponse{} } func (m *ReadVolumeFileStatusResponse) String() string { return proto.CompactTextString(m) } func (*ReadVolumeFileStatusResponse) ProtoMessage() {} -func (*ReadVolumeFileStatusResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{35} } +func (*ReadVolumeFileStatusResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{39} } func (m *ReadVolumeFileStatusResponse) GetVolumeId() uint32 { if m != nil { @@ -864,7 +940,7 @@ type DiskStatus struct { func (m *DiskStatus) Reset() { *m = DiskStatus{} } func (m *DiskStatus) String() string { return proto.CompactTextString(m) } func (*DiskStatus) ProtoMessage() {} -func (*DiskStatus) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{36} } +func (*DiskStatus) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{40} } func (m *DiskStatus) GetDir() string { if m != nil { @@ -907,7 +983,7 @@ type MemStatus struct { func (m *MemStatus) Reset() { *m = MemStatus{} } func (m *MemStatus) String() string { return proto.CompactTextString(m) } func (*MemStatus) ProtoMessage() {} -func (*MemStatus) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{37} } +func (*MemStatus) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{41} } func (m *MemStatus) GetGoroutines() int32 { if m != nil { @@ -993,6 +1069,10 @@ func init() { proto.RegisterType((*VolumeTailSenderResponse)(nil), "volume_server_pb.VolumeTailSenderResponse") proto.RegisterType((*VolumeTailReceiverRequest)(nil), "volume_server_pb.VolumeTailReceiverRequest") proto.RegisterType((*VolumeTailReceiverResponse)(nil), "volume_server_pb.VolumeTailReceiverResponse") + proto.RegisterType((*VolumeEcGenerateSlicesRequest)(nil), "volume_server_pb.VolumeEcGenerateSlicesRequest") + proto.RegisterType((*VolumeEcGenerateSlicesResponse)(nil), "volume_server_pb.VolumeEcGenerateSlicesResponse") + proto.RegisterType((*VolumeEcCopyRequest)(nil), "volume_server_pb.VolumeEcCopyRequest") + proto.RegisterType((*VolumeEcCopyResponse)(nil), "volume_server_pb.VolumeEcCopyResponse") proto.RegisterType((*ReadVolumeFileStatusRequest)(nil), "volume_server_pb.ReadVolumeFileStatusRequest") proto.RegisterType((*ReadVolumeFileStatusResponse)(nil), "volume_server_pb.ReadVolumeFileStatusResponse") proto.RegisterType((*DiskStatus)(nil), "volume_server_pb.DiskStatus") @@ -1029,6 +1109,9 @@ type VolumeServerClient interface { CopyFile(ctx context.Context, in *CopyFileRequest, opts ...grpc.CallOption) (VolumeServer_CopyFileClient, error) VolumeTailSender(ctx context.Context, in *VolumeTailSenderRequest, opts ...grpc.CallOption) (VolumeServer_VolumeTailSenderClient, error) VolumeTailReceiver(ctx context.Context, in *VolumeTailReceiverRequest, opts ...grpc.CallOption) (*VolumeTailReceiverResponse, error) + // erasure coding + VolumeEcGenerateSlices(ctx context.Context, in *VolumeEcGenerateSlicesRequest, opts ...grpc.CallOption) (*VolumeEcGenerateSlicesResponse, error) + VolumeEcCopy(ctx context.Context, in *VolumeEcCopyRequest, opts ...grpc.CallOption) (*VolumeEcCopyResponse, error) } type volumeServerClient struct { @@ -1261,6 +1344,24 @@ func (c *volumeServerClient) VolumeTailReceiver(ctx context.Context, in *VolumeT return out, nil } +func (c *volumeServerClient) VolumeEcGenerateSlices(ctx context.Context, in *VolumeEcGenerateSlicesRequest, opts ...grpc.CallOption) (*VolumeEcGenerateSlicesResponse, error) { + out := new(VolumeEcGenerateSlicesResponse) + err := grpc.Invoke(ctx, "/volume_server_pb.VolumeServer/VolumeEcGenerateSlices", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *volumeServerClient) VolumeEcCopy(ctx context.Context, in *VolumeEcCopyRequest, opts ...grpc.CallOption) (*VolumeEcCopyResponse, error) { + out := new(VolumeEcCopyResponse) + err := grpc.Invoke(ctx, "/volume_server_pb.VolumeServer/VolumeEcCopy", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // Server API for VolumeServer service type VolumeServerServer interface { @@ -1283,6 +1384,9 @@ type VolumeServerServer interface { CopyFile(*CopyFileRequest, VolumeServer_CopyFileServer) error VolumeTailSender(*VolumeTailSenderRequest, VolumeServer_VolumeTailSenderServer) error VolumeTailReceiver(context.Context, *VolumeTailReceiverRequest) (*VolumeTailReceiverResponse, error) + // erasure coding + VolumeEcGenerateSlices(context.Context, *VolumeEcGenerateSlicesRequest) (*VolumeEcGenerateSlicesResponse, error) + VolumeEcCopy(context.Context, *VolumeEcCopyRequest) (*VolumeEcCopyResponse, error) } func RegisterVolumeServerServer(s *grpc.Server, srv VolumeServerServer) { @@ -1604,6 +1708,42 @@ func _VolumeServer_VolumeTailReceiver_Handler(srv interface{}, ctx context.Conte return interceptor(ctx, in, info, handler) } +func _VolumeServer_VolumeEcGenerateSlices_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VolumeEcGenerateSlicesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(VolumeServerServer).VolumeEcGenerateSlices(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/volume_server_pb.VolumeServer/VolumeEcGenerateSlices", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(VolumeServerServer).VolumeEcGenerateSlices(ctx, req.(*VolumeEcGenerateSlicesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _VolumeServer_VolumeEcCopy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VolumeEcCopyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(VolumeServerServer).VolumeEcCopy(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/volume_server_pb.VolumeServer/VolumeEcCopy", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(VolumeServerServer).VolumeEcCopy(ctx, req.(*VolumeEcCopyRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _VolumeServer_serviceDesc = grpc.ServiceDesc{ ServiceName: "volume_server_pb.VolumeServer", HandlerType: (*VolumeServerServer)(nil), @@ -1664,6 +1804,14 @@ var _VolumeServer_serviceDesc = grpc.ServiceDesc{ MethodName: "VolumeTailReceiver", Handler: _VolumeServer_VolumeTailReceiver_Handler, }, + { + MethodName: "VolumeEcGenerateSlices", + Handler: _VolumeServer_VolumeEcGenerateSlices_Handler, + }, + { + MethodName: "VolumeEcCopy", + Handler: _VolumeServer_VolumeEcCopy_Handler, + }, }, Streams: []grpc.StreamDesc{ { @@ -1688,95 +1836,101 @@ var _VolumeServer_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("volume_server.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 1436 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xc4, 0x58, 0x4b, 0x73, 0xd4, 0xc6, - 0x13, 0xb7, 0xd8, 0xb5, 0xbd, 0xee, 0x5d, 0x9b, 0x65, 0x6c, 0xf0, 0x7a, 0x79, 0x19, 0xc1, 0x1f, - 0x96, 0xc7, 0xdf, 0x10, 0xa8, 0x24, 0x24, 0x39, 0x24, 0x60, 0x92, 0x0a, 0x55, 0x01, 0xaa, 0x64, - 0xa0, 0x92, 0x4a, 0xaa, 0x54, 0x63, 0xa9, 0x8d, 0x55, 0xd6, 0x4a, 0x42, 0x33, 0x72, 0x70, 0x2a, - 0xb7, 0xe4, 0x13, 0xe4, 0x2b, 0xe4, 0xc6, 0x21, 0xd7, 0x7c, 0xaa, 0x7c, 0x82, 0x5c, 0x52, 0xf3, - 0x90, 0x76, 0xf5, 0xf2, 0x8a, 0x70, 0xc8, 0x6d, 0xb6, 0xa7, 0xdf, 0xea, 0xee, 0xf9, 0xf5, 0xc2, - 0xea, 0x61, 0xe8, 0x27, 0x63, 0xb4, 0x19, 0xc6, 0x87, 0x18, 0x6f, 0x45, 0x71, 0xc8, 0x43, 0xd2, - 0xcf, 0x11, 0xed, 0x68, 0xd7, 0xbc, 0x0d, 0xe4, 0x21, 0xe5, 0xce, 0xfe, 0x23, 0xf4, 0x91, 0xa3, - 0x85, 0xaf, 0x13, 0x64, 0x9c, 0x6c, 0x40, 0x67, 0xcf, 0xf3, 0xd1, 0xf6, 0x5c, 0x36, 0x30, 0x36, - 0x5b, 0xa3, 0x25, 0x6b, 0x51, 0xfc, 0x7e, 0xec, 0x32, 0xf3, 0x19, 0xac, 0xe6, 0x04, 0x58, 0x14, - 0x06, 0x0c, 0xc9, 0x7d, 0x58, 0x8c, 0x91, 0x25, 0x3e, 0x57, 0x02, 0xdd, 0xbb, 0x17, 0xb6, 0x8a, - 0xb6, 0xb6, 0x32, 0x91, 0xc4, 0xe7, 0x56, 0xca, 0x6e, 0x7a, 0xd0, 0x9b, 0xbe, 0x20, 0xeb, 0xb0, - 0xa8, 0x6d, 0x0f, 0x8c, 0x4d, 0x63, 0xb4, 0x64, 0x2d, 0x28, 0xd3, 0xe4, 0x0c, 0x2c, 0x30, 0x4e, - 0x79, 0xc2, 0x06, 0x27, 0x36, 0x8d, 0xd1, 0xbc, 0xa5, 0x7f, 0x91, 0x35, 0x98, 0xc7, 0x38, 0x0e, - 0xe3, 0x41, 0x4b, 0xb2, 0xab, 0x1f, 0x84, 0x40, 0x9b, 0x79, 0x3f, 0xe1, 0xa0, 0xbd, 0x69, 0x8c, - 0x96, 0x2d, 0x79, 0x36, 0x17, 0x61, 0xfe, 0xcb, 0x71, 0xc4, 0x8f, 0xcc, 0x8f, 0x61, 0xf0, 0x92, - 0x3a, 0x49, 0x32, 0x7e, 0x29, 0x7d, 0xdc, 0xde, 0x47, 0xe7, 0x20, 0x8d, 0xfd, 0x2c, 0x2c, 0x69, - 0xcf, 0xb5, 0x07, 0xcb, 0x56, 0x47, 0x11, 0x1e, 0xbb, 0xe6, 0x17, 0xb0, 0x51, 0x21, 0xa8, 0x73, - 0x70, 0x19, 0x96, 0x5f, 0xd1, 0x78, 0x97, 0xbe, 0x42, 0x3b, 0xa6, 0xdc, 0x0b, 0xa5, 0xb4, 0x61, - 0xf5, 0x34, 0xd1, 0x12, 0x34, 0xf3, 0x7b, 0x18, 0xe6, 0x34, 0x84, 0xe3, 0x88, 0x3a, 0xbc, 0x89, - 0x71, 0xb2, 0x09, 0xdd, 0x28, 0x46, 0xea, 0xfb, 0xa1, 0x43, 0x39, 0xca, 0x2c, 0xb4, 0xac, 0x69, - 0x92, 0x79, 0x1e, 0xce, 0x56, 0x2a, 0x57, 0x0e, 0x9a, 0xf7, 0x0b, 0xde, 0x87, 0xe3, 0xb1, 0xd7, - 0xc8, 0xb4, 0x79, 0xae, 0xe4, 0xb5, 0x94, 0xd4, 0x7a, 0x3f, 0x29, 0xdc, 0xfa, 0x48, 0x83, 0x24, - 0x6a, 0xa4, 0xb8, 0xe8, 0x71, 0x2a, 0x9a, 0x69, 0x5e, 0x57, 0xc5, 0xb1, 0x1d, 0xfa, 0x3e, 0x3a, - 0xdc, 0x0b, 0x83, 0x54, 0xed, 0x05, 0x00, 0x27, 0x23, 0xea, 0x52, 0x99, 0xa2, 0x98, 0x43, 0x18, - 0x94, 0x45, 0xb5, 0xda, 0xb7, 0x06, 0x9c, 0x7e, 0xa0, 0x93, 0xa6, 0x0c, 0x37, 0xfa, 0x00, 0x79, - 0x93, 0x27, 0x8a, 0x26, 0x8b, 0x1f, 0xa8, 0x55, 0xfa, 0x40, 0x82, 0x23, 0xc6, 0xc8, 0xf7, 0x1c, - 0x2a, 0x55, 0xb4, 0xa5, 0x8a, 0x69, 0x12, 0xe9, 0x43, 0x8b, 0x73, 0x7f, 0x30, 0x2f, 0x6f, 0xc4, - 0xd1, 0x1c, 0xc0, 0x99, 0xa2, 0xaf, 0x3a, 0x8c, 0x8f, 0x60, 0x5d, 0x51, 0x76, 0x8e, 0x02, 0x67, - 0x47, 0x76, 0x43, 0xa3, 0xa4, 0xff, 0x6d, 0xc0, 0xa0, 0x2c, 0xa8, 0xab, 0xf8, 0x7d, 0x33, 0xf0, - 0xae, 0xf1, 0x91, 0x8b, 0xd0, 0xe5, 0xd4, 0xf3, 0xed, 0x70, 0x6f, 0x8f, 0x21, 0x1f, 0x2c, 0x6c, - 0x1a, 0xa3, 0xb6, 0x05, 0x82, 0xf4, 0x4c, 0x52, 0xc8, 0x75, 0xe8, 0x3b, 0xaa, 0x92, 0xed, 0x18, - 0x0f, 0x3d, 0x26, 0x34, 0x2f, 0x4a, 0xc7, 0x4e, 0x3a, 0x69, 0x85, 0x2b, 0x32, 0x31, 0x61, 0xd9, - 0x73, 0xdf, 0xd8, 0x72, 0x80, 0xc8, 0xf6, 0xef, 0x48, 0x6d, 0x5d, 0xcf, 0x7d, 0xf3, 0x95, 0xe7, - 0xe3, 0x8e, 0x98, 0x02, 0x2f, 0xe1, 0x9c, 0x0a, 0xfe, 0x71, 0xe0, 0xc4, 0x38, 0xc6, 0x80, 0x53, - 0x7f, 0x3b, 0x8c, 0x8e, 0x1a, 0x95, 0xc0, 0x06, 0x74, 0x98, 0x17, 0x38, 0x68, 0x07, 0x6a, 0x0c, - 0xb5, 0xad, 0x45, 0xf9, 0xfb, 0x29, 0x33, 0x1f, 0xc2, 0xf9, 0x1a, 0xbd, 0x3a, 0xb3, 0x97, 0xa0, - 0x27, 0x1d, 0x73, 0xc2, 0x80, 0x63, 0xc0, 0xa5, 0xee, 0x9e, 0xd5, 0x15, 0xb4, 0x6d, 0x45, 0x32, - 0x3f, 0x00, 0xa2, 0x74, 0x3c, 0x09, 0x93, 0xa0, 0x59, 0x6b, 0x9e, 0x86, 0xd5, 0x9c, 0x88, 0xae, - 0x8d, 0x7b, 0xb0, 0xa6, 0xc8, 0x2f, 0x82, 0x71, 0x63, 0x5d, 0xeb, 0x70, 0xba, 0x20, 0xa4, 0xb5, - 0xdd, 0x4d, 0x8d, 0xe4, 0xdf, 0x89, 0x63, 0x95, 0x9d, 0x49, 0x3d, 0xc8, 0x3f, 0x15, 0xe6, 0x1f, - 0x06, 0x9c, 0x4a, 0xc7, 0x48, 0xc3, 0xac, 0xbf, 0x63, 0xd9, 0xb5, 0x6a, 0xcb, 0xae, 0x3d, 0x29, - 0xbb, 0x11, 0xf4, 0x59, 0x98, 0xc4, 0x0e, 0xda, 0x2e, 0xe5, 0xd4, 0x0e, 0x42, 0x17, 0x75, 0x55, - 0xae, 0x28, 0xfa, 0x23, 0xca, 0xe9, 0xd3, 0xd0, 0x45, 0xf3, 0xf3, 0xf4, 0xa3, 0xe4, 0xbe, 0xe6, - 0x75, 0x38, 0xe5, 0x53, 0xc6, 0x6d, 0x1a, 0x45, 0x18, 0xb8, 0x36, 0xe5, 0xa2, 0x24, 0x0c, 0x59, - 0x12, 0x2b, 0xe2, 0xe2, 0x81, 0xa4, 0x3f, 0xe0, 0x4f, 0x99, 0xf9, 0x9b, 0x01, 0x27, 0x85, 0xac, - 0x28, 0xc1, 0x46, 0xf1, 0xf6, 0xa1, 0x85, 0x6f, 0xb8, 0x0e, 0x54, 0x1c, 0xc9, 0x6d, 0x58, 0xd5, - 0xb5, 0xee, 0x85, 0xc1, 0xa4, 0x0d, 0x5a, 0x52, 0x90, 0x4c, 0xae, 0xb2, 0x4e, 0xb8, 0x08, 0x5d, - 0xc6, 0xc3, 0x28, 0xed, 0xaa, 0xb6, 0xea, 0x2a, 0x41, 0x52, 0x5d, 0x65, 0x7e, 0x08, 0xfd, 0x89, - 0x4f, 0xcd, 0x2b, 0xf4, 0x17, 0x23, 0x1d, 0x3a, 0xcf, 0xa9, 0xe7, 0xef, 0x60, 0xe0, 0x62, 0xfc, - 0x9e, 0x9d, 0x43, 0xee, 0xc0, 0x9a, 0xe7, 0xfa, 0x68, 0x73, 0x6f, 0x8c, 0x61, 0xc2, 0x6d, 0x86, - 0x4e, 0x18, 0xb8, 0x2c, 0x8d, 0x4e, 0xdc, 0x3d, 0x57, 0x57, 0x3b, 0xea, 0xc6, 0xfc, 0x35, 0x9b, - 0x60, 0xd3, 0x5e, 0x4c, 0xde, 0xe1, 0x00, 0x51, 0x28, 0xdc, 0x47, 0xea, 0x62, 0xac, 0xc3, 0xe8, - 0x29, 0xe2, 0xd7, 0x92, 0x26, 0xf2, 0xa3, 0x99, 0x76, 0x43, 0xf7, 0x48, 0x7a, 0xd4, 0xb3, 0x40, - 0x91, 0x1e, 0x86, 0xee, 0x91, 0x1c, 0x25, 0xcc, 0x96, 0x9f, 0xd8, 0xd9, 0x4f, 0x82, 0x03, 0xe9, - 0x4d, 0xc7, 0xea, 0x7a, 0xec, 0x1b, 0xca, 0xf8, 0xb6, 0x20, 0x99, 0x7f, 0x1a, 0xb0, 0x31, 0x71, - 0xc3, 0x42, 0x07, 0xbd, 0xc3, 0xff, 0x20, 0x1d, 0x42, 0x42, 0xd7, 0x72, 0x0e, 0x74, 0xe9, 0x72, - 0x27, 0xea, 0x4e, 0x4f, 0x7c, 0x79, 0x23, 0x1f, 0xf4, 0x0a, 0xc7, 0x75, 0x8b, 0x7e, 0x0a, 0x67, - 0x2d, 0xa4, 0xae, 0xe2, 0x90, 0x83, 0xb3, 0xf9, 0xe3, 0xf2, 0xd7, 0x09, 0x38, 0x57, 0x2d, 0xdc, - 0xe4, 0x81, 0xf9, 0x0c, 0x86, 0xd9, 0x00, 0x17, 0xf1, 0x33, 0x4e, 0xc7, 0x51, 0x96, 0x01, 0x95, - 0xa8, 0x75, 0x3d, 0xcd, 0x9f, 0xa7, 0xf7, 0x69, 0x1a, 0x4a, 0xd3, 0xbf, 0x55, 0x9a, 0xfe, 0xc2, - 0x80, 0x4b, 0x79, 0x9d, 0x01, 0xd5, 0x26, 0xeb, 0x2e, 0xe5, 0x75, 0x06, 0x32, 0x61, 0x69, 0x60, - 0x5e, 0x19, 0xd0, 0xfc, 0xd2, 0xc0, 0x79, 0x00, 0xdd, 0x43, 0x49, 0x90, 0xbe, 0x66, 0x4b, 0xaa, - 0x83, 0x92, 0xa0, 0xb6, 0x91, 0x17, 0x6b, 0x1b, 0x39, 0x3f, 0xfb, 0x3a, 0x25, 0x9c, 0xf3, 0x2d, - 0xc0, 0x23, 0x8f, 0x1d, 0xa8, 0x24, 0x8b, 0xc9, 0xe1, 0x7a, 0xb1, 0x86, 0x43, 0xe2, 0x28, 0x28, - 0xd4, 0xf7, 0x75, 0xea, 0xc4, 0x51, 0x40, 0xe3, 0x84, 0xa1, 0xab, 0xb3, 0x23, 0xcf, 0x82, 0xb6, - 0x17, 0x23, 0xea, 0x04, 0xc8, 0xb3, 0xf9, 0xbb, 0x01, 0x4b, 0x4f, 0x70, 0xac, 0x35, 0x5f, 0x00, - 0x78, 0x15, 0xc6, 0x61, 0xc2, 0xbd, 0x00, 0xd5, 0xa0, 0x9b, 0xb7, 0xa6, 0x28, 0xff, 0xde, 0x8e, - 0x84, 0xea, 0xe8, 0xef, 0xe9, 0x64, 0xca, 0xb3, 0xa0, 0xed, 0x23, 0x8d, 0x74, 0xfe, 0xe4, 0x59, - 0x00, 0x7d, 0xc6, 0xa9, 0x73, 0x20, 0x93, 0xd5, 0xb6, 0xd4, 0x8f, 0xbb, 0x6f, 0x57, 0xa0, 0x37, - 0x5d, 0xda, 0xe4, 0x07, 0xe8, 0x4e, 0x6d, 0x28, 0xe4, 0x4a, 0x79, 0x11, 0x29, 0x6f, 0x3c, 0xc3, - 0xff, 0xcd, 0xe0, 0xd2, 0x8d, 0x31, 0x47, 0x02, 0x38, 0x55, 0xda, 0x00, 0xc8, 0x8d, 0xb2, 0x74, - 0xdd, 0x7e, 0x31, 0xbc, 0xd9, 0x88, 0x37, 0xb3, 0xc7, 0x61, 0xb5, 0x02, 0xd2, 0x93, 0x5b, 0x33, - 0xb4, 0xe4, 0xd6, 0x8a, 0xe1, 0xff, 0x1b, 0x72, 0x67, 0x56, 0x5f, 0x03, 0x29, 0xe3, 0x7d, 0x72, - 0x73, 0xa6, 0x9a, 0xc9, 0x3e, 0x31, 0xbc, 0xd5, 0x8c, 0xb9, 0x36, 0x50, 0xb5, 0x09, 0xcc, 0x0c, - 0x34, 0xb7, 0x6b, 0xcc, 0x0c, 0xb4, 0xb0, 0x5e, 0xcc, 0x91, 0x03, 0xe8, 0x17, 0xb7, 0x04, 0x72, - 0xbd, 0x6e, 0x75, 0x2d, 0x2d, 0x21, 0xc3, 0x1b, 0x4d, 0x58, 0x33, 0x63, 0x08, 0x2b, 0x79, 0x24, - 0x4f, 0xae, 0x95, 0xe5, 0x2b, 0xf7, 0x92, 0xe1, 0x68, 0x36, 0xe3, 0x74, 0x4c, 0x45, 0x74, 0x5f, - 0x15, 0x53, 0xcd, 0xea, 0x50, 0x15, 0x53, 0xdd, 0xb2, 0x60, 0xce, 0x91, 0x9f, 0x53, 0xc8, 0x58, - 0x40, 0xbd, 0x64, 0xab, 0x4e, 0x4d, 0x35, 0xec, 0x1e, 0xde, 0x6e, 0xcc, 0x9f, 0xda, 0xbe, 0x63, - 0x88, 0x5e, 0x9f, 0x02, 0xbf, 0x55, 0xbd, 0x5e, 0x86, 0xd3, 0x55, 0xbd, 0x5e, 0x85, 0xa0, 0xe7, - 0xc8, 0x2e, 0x2c, 0xe7, 0xe0, 0x30, 0xb9, 0x5a, 0x27, 0x99, 0x07, 0xd9, 0xc3, 0x6b, 0x33, 0xf9, - 0x32, 0x1b, 0x76, 0x3a, 0xbd, 0xf4, 0xb8, 0xaa, 0x75, 0x2e, 0x3f, 0xaf, 0xae, 0xce, 0x62, 0xcb, - 0x0c, 0x7c, 0x07, 0x30, 0x41, 0xaf, 0xe4, 0x72, 0x9d, 0xdc, 0xf4, 0xa7, 0xb8, 0x72, 0x3c, 0x53, - 0xa6, 0xfa, 0x47, 0x58, 0xab, 0x7a, 0xe9, 0x49, 0x45, 0x17, 0x1e, 0x03, 0x27, 0x86, 0x5b, 0x4d, - 0xd9, 0x33, 0xc3, 0x2f, 0xa0, 0x93, 0x62, 0x57, 0x72, 0xa9, 0x2c, 0x5d, 0xc0, 0xda, 0x43, 0xf3, - 0x38, 0x96, 0xa9, 0x6a, 0x1a, 0xa7, 0x8d, 0x33, 0x01, 0x95, 0xf5, 0x8d, 0x53, 0x82, 0xbf, 0xf5, - 0x8d, 0x53, 0xc6, 0xa8, 0xd2, 0xdc, 0xeb, 0x74, 0xaf, 0x98, 0xc6, 0x60, 0x95, 0x43, 0xb6, 0x0e, - 0x62, 0x56, 0x0e, 0xd9, 0x7a, 0x58, 0x37, 0xb7, 0xbb, 0x20, 0xff, 0x07, 0xbc, 0xf7, 0x4f, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x5d, 0xbf, 0x08, 0x06, 0x1e, 0x14, 0x00, 0x00, + // 1534 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xc4, 0x58, 0xcb, 0x6f, 0xd4, 0xd6, + 0x1a, 0x8f, 0x99, 0xc9, 0xeb, 0x9b, 0x04, 0x86, 0x93, 0x90, 0x4c, 0x0c, 0x09, 0x83, 0xe1, 0xc2, + 0xf0, 0xb8, 0x81, 0x0b, 0xba, 0xf7, 0xd2, 0x87, 0xd4, 0x42, 0xa0, 0x6d, 0xa4, 0x02, 0x92, 0x03, + 0xa8, 0x55, 0x2b, 0x59, 0x27, 0xf6, 0x17, 0x62, 0xc5, 0x63, 0x1b, 0xfb, 0x38, 0x4d, 0xaa, 0x76, + 0xd5, 0xae, 0xba, 0xec, 0xb6, 0xcb, 0xee, 0xba, 0xe8, 0xb6, 0x7f, 0x55, 0xff, 0x82, 0x6e, 0xaa, + 0xf3, 0xb0, 0x67, 0xfc, 0xca, 0x98, 0x52, 0xa9, 0xbb, 0x33, 0xdf, 0xf9, 0x5e, 0xe7, 0xf3, 0xf7, + 0xfa, 0x0d, 0x2c, 0x1d, 0x06, 0x5e, 0x32, 0x44, 0x2b, 0xc6, 0xe8, 0x10, 0xa3, 0xcd, 0x30, 0x0a, + 0x58, 0x40, 0xba, 0x39, 0xa2, 0x15, 0xee, 0x1a, 0xb7, 0x81, 0x3c, 0xa4, 0xcc, 0xde, 0x7f, 0x84, + 0x1e, 0x32, 0x34, 0xf1, 0x75, 0x82, 0x31, 0x23, 0x6b, 0x30, 0xb7, 0xe7, 0x7a, 0x68, 0xb9, 0x4e, + 0xdc, 0xd3, 0xfa, 0xad, 0xc1, 0xbc, 0x39, 0xcb, 0x7f, 0x6f, 0x3b, 0xb1, 0xf1, 0x0c, 0x96, 0x72, + 0x02, 0x71, 0x18, 0xf8, 0x31, 0x92, 0xfb, 0x30, 0x1b, 0x61, 0x9c, 0x78, 0x4c, 0x0a, 0x74, 0xee, + 0x6e, 0x6c, 0x16, 0x6d, 0x6d, 0x66, 0x22, 0x89, 0xc7, 0xcc, 0x94, 0xdd, 0x70, 0x61, 0x61, 0xfc, + 0x82, 0xac, 0xc2, 0xac, 0xb2, 0xdd, 0xd3, 0xfa, 0xda, 0x60, 0xde, 0x9c, 0x91, 0xa6, 0xc9, 0x0a, + 0xcc, 0xc4, 0x8c, 0xb2, 0x24, 0xee, 0x9d, 0xea, 0x6b, 0x83, 0x69, 0x53, 0xfd, 0x22, 0xcb, 0x30, + 0x8d, 0x51, 0x14, 0x44, 0xbd, 0x96, 0x60, 0x97, 0x3f, 0x08, 0x81, 0x76, 0xec, 0x7e, 0x8d, 0xbd, + 0x76, 0x5f, 0x1b, 0x2c, 0x9a, 0xe2, 0x6c, 0xcc, 0xc2, 0xf4, 0xe3, 0x61, 0xc8, 0x8e, 0x8d, 0xff, + 0x43, 0xef, 0x25, 0xb5, 0x93, 0x64, 0xf8, 0x52, 0xf8, 0xb8, 0xb5, 0x8f, 0xf6, 0x41, 0xfa, 0xf6, + 0xf3, 0x30, 0xaf, 0x3c, 0x57, 0x1e, 0x2c, 0x9a, 0x73, 0x92, 0xb0, 0xed, 0x18, 0x1f, 0xc2, 0x5a, + 0x85, 0xa0, 0x8a, 0xc1, 0x65, 0x58, 0x7c, 0x45, 0xa3, 0x5d, 0xfa, 0x0a, 0xad, 0x88, 0x32, 0x37, + 0x10, 0xd2, 0x9a, 0xb9, 0xa0, 0x88, 0x26, 0xa7, 0x19, 0x5f, 0x80, 0x9e, 0xd3, 0x10, 0x0c, 0x43, + 0x6a, 0xb3, 0x26, 0xc6, 0x49, 0x1f, 0x3a, 0x61, 0x84, 0xd4, 0xf3, 0x02, 0x9b, 0x32, 0x14, 0x51, + 0x68, 0x99, 0xe3, 0x24, 0x63, 0x1d, 0xce, 0x57, 0x2a, 0x97, 0x0e, 0x1a, 0xf7, 0x0b, 0xde, 0x07, + 0xc3, 0xa1, 0xdb, 0xc8, 0xb4, 0x71, 0xa1, 0xe4, 0xb5, 0x90, 0x54, 0x7a, 0xdf, 0x29, 0xdc, 0x7a, + 0x48, 0xfd, 0x24, 0x6c, 0xa4, 0xb8, 0xe8, 0x71, 0x2a, 0x9a, 0x69, 0x5e, 0x95, 0xc9, 0xb1, 0x15, + 0x78, 0x1e, 0xda, 0xcc, 0x0d, 0xfc, 0x54, 0xed, 0x06, 0x80, 0x9d, 0x11, 0x55, 0xaa, 0x8c, 0x51, + 0x0c, 0x1d, 0x7a, 0x65, 0x51, 0xa5, 0xf6, 0x17, 0x0d, 0xce, 0x3d, 0x50, 0x41, 0x93, 0x86, 0x1b, + 0x7d, 0x80, 0xbc, 0xc9, 0x53, 0x45, 0x93, 0xc5, 0x0f, 0xd4, 0x2a, 0x7d, 0x20, 0xce, 0x11, 0x61, + 0xe8, 0xb9, 0x36, 0x15, 0x2a, 0xda, 0x42, 0xc5, 0x38, 0x89, 0x74, 0xa1, 0xc5, 0x98, 0xd7, 0x9b, + 0x16, 0x37, 0xfc, 0x68, 0xf4, 0x60, 0xa5, 0xe8, 0xab, 0x7a, 0xc6, 0xff, 0x60, 0x55, 0x52, 0x76, + 0x8e, 0x7d, 0x7b, 0x47, 0x54, 0x43, 0xa3, 0xa0, 0xff, 0xa1, 0x41, 0xaf, 0x2c, 0xa8, 0xb2, 0xf8, + 0x6d, 0x23, 0xf0, 0xa6, 0xef, 0x23, 0x17, 0xa1, 0xc3, 0xa8, 0xeb, 0x59, 0xc1, 0xde, 0x5e, 0x8c, + 0xac, 0x37, 0xd3, 0xd7, 0x06, 0x6d, 0x13, 0x38, 0xe9, 0x99, 0xa0, 0x90, 0xeb, 0xd0, 0xb5, 0x65, + 0x26, 0x5b, 0x11, 0x1e, 0xba, 0x31, 0xd7, 0x3c, 0x2b, 0x1c, 0x3b, 0x63, 0xa7, 0x19, 0x2e, 0xc9, + 0xc4, 0x80, 0x45, 0xd7, 0x39, 0xb2, 0x44, 0x03, 0x11, 0xe5, 0x3f, 0x27, 0xb4, 0x75, 0x5c, 0xe7, + 0xe8, 0x23, 0xd7, 0xc3, 0x1d, 0xde, 0x05, 0x5e, 0xc2, 0x05, 0xf9, 0xf8, 0x6d, 0xdf, 0x8e, 0x70, + 0x88, 0x3e, 0xa3, 0xde, 0x56, 0x10, 0x1e, 0x37, 0x4a, 0x81, 0x35, 0x98, 0x8b, 0x5d, 0xdf, 0x46, + 0xcb, 0x97, 0x6d, 0xa8, 0x6d, 0xce, 0x8a, 0xdf, 0x4f, 0x63, 0xe3, 0x21, 0xac, 0xd7, 0xe8, 0x55, + 0x91, 0xbd, 0x04, 0x0b, 0xc2, 0x31, 0x3b, 0xf0, 0x19, 0xfa, 0x4c, 0xe8, 0x5e, 0x30, 0x3b, 0x9c, + 0xb6, 0x25, 0x49, 0xc6, 0x7f, 0x80, 0x48, 0x1d, 0x4f, 0x82, 0xc4, 0x6f, 0x56, 0x9a, 0xe7, 0x60, + 0x29, 0x27, 0xa2, 0x72, 0xe3, 0x1e, 0x2c, 0x4b, 0xf2, 0x0b, 0x7f, 0xd8, 0x58, 0xd7, 0x2a, 0x9c, + 0x2b, 0x08, 0x29, 0x6d, 0x77, 0x53, 0x23, 0xf9, 0x39, 0x71, 0xa2, 0xb2, 0x95, 0xd4, 0x83, 0xfc, + 0xa8, 0x30, 0x7e, 0xd5, 0xe0, 0x6c, 0xda, 0x46, 0x1a, 0x46, 0xfd, 0x0d, 0xd3, 0xae, 0x55, 0x9b, + 0x76, 0xed, 0x51, 0xda, 0x0d, 0xa0, 0x1b, 0x07, 0x49, 0x64, 0xa3, 0xe5, 0x50, 0x46, 0x2d, 0x3f, + 0x70, 0x50, 0x65, 0xe5, 0x69, 0x49, 0x7f, 0x44, 0x19, 0x7d, 0x1a, 0x38, 0x68, 0x7c, 0x90, 0x7e, + 0x94, 0xdc, 0xd7, 0xbc, 0x0e, 0x67, 0x3d, 0x1a, 0x33, 0x8b, 0x86, 0x21, 0xfa, 0x8e, 0x45, 0x19, + 0x4f, 0x09, 0x4d, 0xa4, 0xc4, 0x69, 0x7e, 0xf1, 0x40, 0xd0, 0x1f, 0xb0, 0xa7, 0xb1, 0xf1, 0xa3, + 0x06, 0x67, 0xb8, 0x2c, 0x4f, 0xc1, 0x46, 0xef, 0xed, 0x42, 0x0b, 0x8f, 0x98, 0x7a, 0x28, 0x3f, + 0x92, 0xdb, 0xb0, 0xa4, 0x72, 0xdd, 0x0d, 0xfc, 0x51, 0x19, 0xb4, 0x84, 0x20, 0x19, 0x5d, 0x65, + 0x95, 0x70, 0x11, 0x3a, 0x31, 0x0b, 0xc2, 0xb4, 0xaa, 0xda, 0xb2, 0xaa, 0x38, 0x49, 0x56, 0x95, + 0xf1, 0x5f, 0xe8, 0x8e, 0x7c, 0x6a, 0x9e, 0xa1, 0xdf, 0x69, 0x69, 0xd3, 0x79, 0x4e, 0x5d, 0x6f, + 0x07, 0x7d, 0x07, 0xa3, 0xb7, 0xac, 0x1c, 0x72, 0x07, 0x96, 0x5d, 0xc7, 0x43, 0x8b, 0xb9, 0x43, + 0x0c, 0x12, 0x66, 0xc5, 0x68, 0x07, 0xbe, 0x13, 0xa7, 0xaf, 0xe3, 0x77, 0xcf, 0xe5, 0xd5, 0x8e, + 0xbc, 0x31, 0xbe, 0xcf, 0x3a, 0xd8, 0xb8, 0x17, 0xa3, 0x39, 0xec, 0x23, 0x72, 0x85, 0xfb, 0x48, + 0x1d, 0x8c, 0xd4, 0x33, 0x16, 0x24, 0xf1, 0x13, 0x41, 0xe3, 0xf1, 0x51, 0x4c, 0xbb, 0x81, 0x73, + 0x2c, 0x3c, 0x5a, 0x30, 0x41, 0x92, 0x1e, 0x06, 0xce, 0xb1, 0x68, 0x25, 0xb1, 0x25, 0x3e, 0xb1, + 0xbd, 0x9f, 0xf8, 0x07, 0xc2, 0x9b, 0x39, 0xb3, 0xe3, 0xc6, 0x9f, 0xd2, 0x98, 0x6d, 0x71, 0x92, + 0xf1, 0x9b, 0x06, 0x6b, 0x23, 0x37, 0x4c, 0xb4, 0xd1, 0x3d, 0xfc, 0x07, 0xc2, 0xc1, 0x25, 0x54, + 0x2e, 0xe7, 0x96, 0x2e, 0x95, 0xee, 0x44, 0xde, 0xa9, 0x8e, 0x2f, 0x6e, 0xc4, 0x40, 0xaf, 0x70, + 0x5c, 0x95, 0xe8, 0xfb, 0x69, 0x2b, 0x7b, 0x6c, 0x7f, 0x8c, 0x3e, 0x46, 0x94, 0xe1, 0x8e, 0xe7, + 0xda, 0xd8, 0x6c, 0xbc, 0xf4, 0x61, 0xa3, 0x4e, 0x5a, 0xe9, 0xff, 0x49, 0x4b, 0xfb, 0xc9, 0x63, + 0xfb, 0x6f, 0x6b, 0x02, 0xeb, 0x00, 0x68, 0x5b, 0xae, 0xef, 0xe0, 0x11, 0xf2, 0x60, 0xb5, 0x06, + 0x8b, 0xe6, 0x3c, 0xda, 0xdb, 0x92, 0xf0, 0x06, 0xf5, 0x9e, 0x35, 0xae, 0xd4, 0x39, 0xe5, 0xf5, + 0xbb, 0x70, 0xde, 0x44, 0xea, 0xc8, 0x3b, 0x31, 0x4e, 0x9a, 0x8f, 0xdc, 0xdf, 0x4f, 0xc1, 0x85, + 0x6a, 0xe1, 0x26, 0x63, 0xf7, 0x3d, 0xd0, 0xb3, 0xb1, 0xc6, 0xb3, 0x22, 0x66, 0x74, 0x18, 0x66, + 0x79, 0x21, 0xd3, 0x67, 0x55, 0xcd, 0xb8, 0xe7, 0xe9, 0x7d, 0x9a, 0x1c, 0xa5, 0x99, 0xd8, 0x2a, + 0xcd, 0x44, 0x6e, 0xc0, 0xa1, 0xac, 0xce, 0x80, 0x6c, 0x1e, 0xab, 0x0e, 0x65, 0x75, 0x06, 0x32, + 0x61, 0x61, 0x60, 0x5a, 0x1a, 0x50, 0xfc, 0xc2, 0xc0, 0x3a, 0x80, 0xea, 0x2c, 0x89, 0x9f, 0xce, + 0xf8, 0x79, 0xd9, 0x57, 0x12, 0xbf, 0xb6, 0xbd, 0xcd, 0xd6, 0xb6, 0xb7, 0x7c, 0x32, 0xcc, 0x95, + 0xb6, 0xbf, 0xcf, 0x00, 0x1e, 0xb9, 0xf1, 0x81, 0x0c, 0x32, 0xef, 0xa7, 0x8e, 0x1b, 0xa9, 0x25, + 0x91, 0x1f, 0x39, 0x85, 0x7a, 0x9e, 0x0a, 0x1d, 0x3f, 0x72, 0xc0, 0x90, 0xc4, 0xe8, 0xa8, 0xe8, + 0x88, 0x33, 0xa7, 0xed, 0x45, 0x88, 0x2a, 0x00, 0xe2, 0x6c, 0xfc, 0xac, 0xc1, 0xfc, 0x13, 0x1c, + 0x2a, 0xcd, 0x1b, 0x00, 0xaf, 0x82, 0x28, 0x48, 0x98, 0xeb, 0xa3, 0x6c, 0xff, 0xd3, 0xe6, 0x18, + 0xe5, 0xaf, 0xdb, 0x11, 0x00, 0x06, 0xbd, 0x3d, 0x15, 0x4c, 0x71, 0xe6, 0xb4, 0x7d, 0xa4, 0xa1, + 0x8a, 0x9f, 0x38, 0x73, 0xf8, 0x13, 0x33, 0x6a, 0x1f, 0x88, 0x60, 0xb5, 0x4d, 0xf9, 0xe3, 0xee, + 0x0f, 0x5d, 0x58, 0x18, 0x2f, 0x78, 0xf2, 0x25, 0x74, 0xc6, 0x70, 0x1b, 0xb9, 0x52, 0x86, 0x67, + 0x65, 0x1c, 0xa8, 0xff, 0x6b, 0x02, 0x97, 0x2a, 0x8c, 0x29, 0xe2, 0xc3, 0xd9, 0x12, 0x2e, 0x22, + 0x37, 0xca, 0xd2, 0x75, 0xa8, 0x4b, 0xbf, 0xd9, 0x88, 0x37, 0xb3, 0xc7, 0x60, 0xa9, 0x02, 0xe8, + 0x90, 0x5b, 0x13, 0xb4, 0xe4, 0xc0, 0x96, 0xfe, 0xef, 0x86, 0xdc, 0x99, 0xd5, 0xd7, 0x40, 0xca, + 0x28, 0x88, 0xdc, 0x9c, 0xa8, 0x66, 0x84, 0xb2, 0xf4, 0x5b, 0xcd, 0x98, 0x6b, 0x1f, 0x2a, 0xf1, + 0xd1, 0xc4, 0x87, 0xe6, 0x10, 0xd8, 0xc4, 0x87, 0x16, 0x40, 0xd7, 0x14, 0x39, 0x80, 0x6e, 0x11, + 0x3b, 0x91, 0xeb, 0x75, 0x80, 0xbe, 0x04, 0xcd, 0xf4, 0x1b, 0x4d, 0x58, 0x33, 0x63, 0x08, 0xa7, + 0xf3, 0xf8, 0x86, 0x5c, 0x2b, 0xcb, 0x57, 0xa2, 0x35, 0x7d, 0x30, 0x99, 0x71, 0xfc, 0x4d, 0x45, + 0xcc, 0x53, 0xf5, 0xa6, 0x1a, 0x40, 0x55, 0xf5, 0xa6, 0x3a, 0x08, 0x65, 0x4c, 0x91, 0x6f, 0xd2, + 0x45, 0xba, 0x80, 0x05, 0xc8, 0x66, 0x9d, 0x9a, 0x6a, 0x30, 0xa2, 0xdf, 0x6e, 0xcc, 0x9f, 0xda, + 0xbe, 0xa3, 0xf1, 0x5a, 0x1f, 0x83, 0x04, 0x55, 0xb5, 0x5e, 0x06, 0x19, 0x55, 0xb5, 0x5e, 0x85, + 0x2b, 0xa6, 0xc8, 0x2e, 0x2c, 0xe6, 0x40, 0x02, 0xb9, 0x5a, 0x27, 0x99, 0x87, 0x1e, 0xfa, 0xb5, + 0x89, 0x7c, 0x99, 0x0d, 0x2b, 0xed, 0x5e, 0xaa, 0x5d, 0xd5, 0x3a, 0x97, 0xef, 0x57, 0x57, 0x27, + 0xb1, 0x65, 0x06, 0x3e, 0x07, 0x18, 0xed, 0xf4, 0xe4, 0x72, 0x9d, 0xdc, 0xf8, 0xa7, 0xb8, 0x72, + 0x32, 0x53, 0xa6, 0xfa, 0x2b, 0x58, 0xae, 0x9a, 0xf4, 0xa4, 0xa2, 0x0a, 0x4f, 0x58, 0x27, 0xf4, + 0xcd, 0xa6, 0xec, 0x99, 0xe1, 0x17, 0x30, 0x97, 0x6e, 0xf4, 0xe4, 0x52, 0x59, 0xba, 0x80, 0x40, + 0x74, 0xe3, 0x24, 0x96, 0xb1, 0x6c, 0x1a, 0xa6, 0x85, 0x33, 0x5a, 0xb5, 0xeb, 0x0b, 0xa7, 0x04, + 0x0a, 0xea, 0x0b, 0xa7, 0xbc, 0xb9, 0x0b, 0x73, 0xaf, 0x53, 0xb4, 0x35, 0xbe, 0x99, 0x56, 0x36, + 0xd9, 0xba, 0xc5, 0xbb, 0xb2, 0xc9, 0xd6, 0x2f, 0xbb, 0x53, 0xe4, 0x5b, 0x58, 0xa9, 0x5e, 0x58, + 0x49, 0x6d, 0xf9, 0xd5, 0x2c, 0xc6, 0xfa, 0x9d, 0xe6, 0x02, 0xe5, 0x64, 0x97, 0xfb, 0x66, 0x7d, + 0xb2, 0xe7, 0x96, 0xe5, 0xfa, 0x64, 0x2f, 0xac, 0xad, 0x53, 0xbb, 0x33, 0xe2, 0xdf, 0xdf, 0x7b, + 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0x2f, 0xf9, 0x4c, 0xc9, 0x14, 0x16, 0x00, 0x00, } diff --git a/weed/server/volume_grpc_copy.go b/weed/server/volume_grpc_copy.go index 6bb61dfba..7b681aa53 100644 --- a/weed/server/volume_grpc_copy.go +++ b/weed/server/volume_grpc_copy.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "io" + "math" "os" "time" @@ -49,37 +50,13 @@ func (vs *VolumeServer) VolumeCopy(ctx context.Context, req *volume_server_pb.Vo volumeFileName = storage.VolumeFileName(volFileInfoResp.Collection, location.Directory, int(req.VolumeId)) // println("source:", volFileInfoResp.String()) - - copyFileClient, err := client.CopyFile(ctx, &volume_server_pb.CopyFileRequest{ - VolumeId: req.VolumeId, - Ext: ".idx", - CompactionRevision: volFileInfoResp.CompactionRevision, - StopOffset: volFileInfoResp.IdxFileSize, - }) - if err != nil { - return fmt.Errorf("failed to start copying volume %d idx file: %v", req.VolumeId, err) - } - - idxFileName = volumeFileName + ".idx" - err = writeToFile(copyFileClient, idxFileName, util.NewWriteThrottler(vs.compactionBytePerSecond)) - if err != nil { - return fmt.Errorf("failed to copy volume %d idx file: %v", req.VolumeId, err) - } - - copyFileClient, err = client.CopyFile(ctx, &volume_server_pb.CopyFileRequest{ - VolumeId: req.VolumeId, - Ext: ".dat", - CompactionRevision: volFileInfoResp.CompactionRevision, - StopOffset: volFileInfoResp.DatFileSize, - }) - if err != nil { - return fmt.Errorf("failed to start copying volume %d dat file: %v", req.VolumeId, err) + // copy ecx file + if err:=vs.doCopyFile(ctx, client, req.VolumeId, volFileInfoResp.CompactionRevision, volFileInfoResp.IdxFileSize, volumeFileName, ".idx"); err!=nil{ + return err } - datFileName = volumeFileName + ".dat" - err = writeToFile(copyFileClient, datFileName, util.NewWriteThrottler(vs.compactionBytePerSecond)) - if err != nil { - return fmt.Errorf("failed to copy volume %d dat file: %v", req.VolumeId, err) + if err:=vs.doCopyFile(ctx, client, req.VolumeId, volFileInfoResp.CompactionRevision, volFileInfoResp.DatFileSize, volumeFileName, ".dat"); err!=nil{ + return err } return nil @@ -109,6 +86,28 @@ func (vs *VolumeServer) VolumeCopy(ctx context.Context, req *volume_server_pb.Vo }, err } +func (vs *VolumeServer) doCopyFile(ctx context.Context, client volume_server_pb.VolumeServerClient, vid uint32, + compactRevision uint32, stopOffset uint64, baseFileName, ext string) error { + + copyFileClient, err := client.CopyFile(ctx, &volume_server_pb.CopyFileRequest{ + VolumeId: vid, + Ext: ext, + CompactionRevision: compactRevision, + StopOffset: stopOffset, + }) + if err != nil { + return fmt.Errorf("failed to start copying volume %d %s file: %v", vid, ext, err) + } + + err = writeToFile(copyFileClient, baseFileName+ext, util.NewWriteThrottler(vs.compactionBytePerSecond)) + if err != nil { + return fmt.Errorf("failed to copy volume %d %s file: %v", vid, ext, err) + } + + return nil + +} + /** only check the the differ of the file size todo: maybe should check the received count and deleted count of the volume @@ -175,6 +174,9 @@ func (vs *VolumeServer) ReadVolumeFileStatus(ctx context.Context, req *volume_se return resp, nil } +// CopyFile client pulls the volume related file from the source server. +// if req.CompactionRevision != math.MaxUint32, it ensures the compact revision is as expected +// The copying still stop at req.StopOffset, but you can set it to math.MaxUint64 in order to read all data. func (vs *VolumeServer) CopyFile(req *volume_server_pb.CopyFileRequest, stream volume_server_pb.VolumeServer_CopyFileServer) error { v := vs.store.GetVolume(needle.VolumeId(req.VolumeId)) @@ -182,7 +184,7 @@ func (vs *VolumeServer) CopyFile(req *volume_server_pb.CopyFileRequest, stream v return fmt.Errorf("not found volume id %d", req.VolumeId) } - if uint32(v.CompactionRevision) != req.CompactionRevision { + if uint32(v.CompactionRevision) != req.CompactionRevision && req.CompactionRevision != math.MaxUint32 { return fmt.Errorf("volume %d is compacted", req.VolumeId) } diff --git a/weed/server/volume_grpc_erasure_coding.go b/weed/server/volume_grpc_erasure_coding.go new file mode 100644 index 000000000..beda234f7 --- /dev/null +++ b/weed/server/volume_grpc_erasure_coding.go @@ -0,0 +1,82 @@ +package weed_server + +import ( + "context" + "fmt" + "math" + + "github.com/chrislusf/seaweedfs/weed/operation" + "github.com/chrislusf/seaweedfs/weed/pb/volume_server_pb" + "github.com/chrislusf/seaweedfs/weed/storage" + "github.com/chrislusf/seaweedfs/weed/storage/erasure_coding" + "github.com/chrislusf/seaweedfs/weed/storage/needle" +) + +/* + +Steps to apply erasure coding to .dat .idx files +0. ensure the volume is readonly +1. client call VolumeEcGenerateSlices to generate the .ecx and .ec01~.ec14 files +2. client ask master for possible servers to hold the ec files, at least 4 servers +3. client call VolumeEcCopy on above target servers to copy ec files from the source server +4. target servers report the new ec files to the master +5. master stores vid -> [14]*DataNode +6. client checks master. If all 14 slices are ready, delete the original .idx, .idx files + + */ + +// VolumeEcGenerateSlices generates the .ecx and .ec01 ~ .ec14 files +func (vs *VolumeServer) VolumeEcGenerateSlices(ctx context.Context, req *volume_server_pb.VolumeEcGenerateSlicesRequest) (*volume_server_pb.VolumeEcGenerateSlicesResponse, error) { + + v := vs.store.GetVolume(needle.VolumeId(req.VolumeId)) + if v == nil { + return nil, fmt.Errorf("volume %d not found", req.VolumeId) + } + baseFileName := v.FileName() + + // write .ecx file + if err := erasure_coding.WriteSortedEcxFile(baseFileName); err != nil { + return nil, fmt.Errorf("WriteSortedEcxFile %s: %v", baseFileName, err) + } + + // write .ec01 ~ .ec14 files + if err := erasure_coding.WriteEcFiles(baseFileName); err != nil { + return nil, fmt.Errorf("WriteEcFiles %s: %v", baseFileName, err) + } + + + return &volume_server_pb.VolumeEcGenerateSlicesResponse{}, nil +} + +// VolumeEcCopy copy the .ecx and some ec data slices +func (vs *VolumeServer) VolumeEcCopy(ctx context.Context, req *volume_server_pb.VolumeEcCopyRequest) (*volume_server_pb.VolumeEcCopyResponse, error) { + + location := vs.store.FindFreeLocation() + if location == nil { + return nil, fmt.Errorf("no space left") + } + + baseFileName := storage.VolumeFileName(req.Collection, location.Directory, int(req.VolumeId)) + + err := operation.WithVolumeServerClient(req.SourceDataNode, vs.grpcDialOption, func(client volume_server_pb.VolumeServerClient) error { + + // copy ecx file + if err:=vs.doCopyFile(ctx, client, req.VolumeId, math.MaxUint32, math.MaxUint64, baseFileName, ".ecx"); err!=nil{ + return err + } + + // copy ec data slices + for _, ecIndex := range req.EcIndexes { + if err:=vs.doCopyFile(ctx, client, req.VolumeId, math.MaxUint32, math.MaxUint64, baseFileName, erasure_coding.ToExt(int(ecIndex))); err!=nil{ + return err + } + } + + return nil + }) + if err != nil { + return nil, fmt.Errorf("VolumeEcCopy volume %d: %v", req.VolumeId, err) + } + + return &volume_server_pb.VolumeEcCopyResponse{}, nil +} diff --git a/weed/storage/erasure_coding/ec_encoder.go b/weed/storage/erasure_coding/ec_encoder.go index 4b5205dee..f4aa17e9d 100644 --- a/weed/storage/erasure_coding/ec_encoder.go +++ b/weed/storage/erasure_coding/ec_encoder.go @@ -6,6 +6,9 @@ import ( "os" "github.com/chrislusf/seaweedfs/weed/glog" + "github.com/chrislusf/seaweedfs/weed/storage" + "github.com/chrislusf/seaweedfs/weed/storage/needle_map" + "github.com/chrislusf/seaweedfs/weed/storage/types" "github.com/klauspost/reedsolomon" ) @@ -16,11 +19,66 @@ const ( ErasureCodingSmallBlockSize = 1024 * 1024 // 1MB ) +// WriteSortedEcxFile generates .ecx file from existing .idx file +// all keys are sorted in ascending order +func WriteSortedEcxFile(baseFileName string) (e error) { + + cm, err := readCompactMap(baseFileName) + if err != nil { + return fmt.Errorf("readCompactMap: %v", err) + } + + ecxFile, err := os.OpenFile(baseFileName+".ecx", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return fmt.Errorf("failed to open dat file: %v", err) + } + defer ecxFile.Close() + + err = cm.AscendingVisit(func(value needle_map.NeedleValue) error { + bytes := value.ToBytes() + _, writeErr := ecxFile.Write(bytes) + return writeErr + }) + + if err != nil { + return fmt.Errorf("failed to open dat file: %v", err) + } + + return nil +} + +// WriteEcFiles generates .ec01 ~ .ec14 files +func WriteEcFiles(baseFileName string) error { + return generateEcFiles(baseFileName, 256*1024, ErasureCodingLargeBlockSize, ErasureCodingSmallBlockSize) +} + +func ToExt(ecIndex int) string { + return fmt.Sprintf(".ec%02d", ecIndex) +} + +func generateEcFiles(baseFileName string, bufferSize int, largeBlockSize int64, smallBlockSize int64) error { + file, err := os.OpenFile(baseFileName+".dat", os.O_RDONLY, 0) + if err != nil { + return fmt.Errorf("failed to open dat file: %v", err) + } + defer file.Close() + + fi, err := file.Stat() + if err != nil { + return fmt.Errorf("failed to stat dat file: %v", err) + } + err = encodeDatFile(fi.Size(), err, baseFileName, bufferSize, largeBlockSize, file, smallBlockSize) + if err != nil { + return fmt.Errorf("encodeDatFile: %v", err) + } + return nil +} + func encodeData(file *os.File, enc reedsolomon.Encoder, startOffset, blockSize int64, buffers [][]byte, outputs []*os.File) error { bufferSize := int64(len(buffers[0])) - batchCount := blockSize/bufferSize - if blockSize%bufferSize!=0 { + batchCount := blockSize / bufferSize + if blockSize%bufferSize != 0 { glog.Fatalf("unexpected block size %d buffer size %d", blockSize, bufferSize) } @@ -34,10 +92,10 @@ func encodeData(file *os.File, enc reedsolomon.Encoder, startOffset, blockSize i return nil } -func openEcFiles(baseFileName string, forRead bool) (files []*os.File, err error){ - for i := 0; i< DataShardsCount+ParityShardsCount; i++{ - fname := fmt.Sprintf("%s.ec%02d", baseFileName, i+1) - openOption := os.O_TRUNC|os.O_CREATE|os.O_WRONLY +func openEcFiles(baseFileName string, forRead bool) (files []*os.File, err error) { + for i := 0; i < DataShardsCount+ParityShardsCount; i++ { + fname := baseFileName + ToExt(i+1) + openOption := os.O_TRUNC | os.O_CREATE | os.O_WRONLY if forRead { openOption = os.O_RDONLY } @@ -50,15 +108,14 @@ func openEcFiles(baseFileName string, forRead bool) (files []*os.File, err error return } -func closeEcFiles(files []*os.File){ - for _, f := range files{ +func closeEcFiles(files []*os.File) { + for _, f := range files { if f != nil { f.Close() } } } - func encodeDataOneBatch(file *os.File, enc reedsolomon.Encoder, startOffset, blockSize int64, buffers [][]byte, outputs []*os.File) error { // read data into buffers @@ -90,3 +147,56 @@ func encodeDataOneBatch(file *os.File, enc reedsolomon.Encoder, startOffset, blo return nil } + +func encodeDatFile(remainingSize int64, err error, baseFileName string, bufferSize int, largeBlockSize int64, file *os.File, smallBlockSize int64) error { + var processedSize int64 + enc, err := reedsolomon.New(DataShardsCount, ParityShardsCount) + if err != nil { + return fmt.Errorf("failed to create encoder: %v", err) + } + buffers := make([][]byte, DataShardsCount+ParityShardsCount) + outputs, err := openEcFiles(baseFileName, false) + defer closeEcFiles(outputs) + if err != nil { + return fmt.Errorf("failed to open dat file: %v", err) + } + for i, _ := range buffers { + buffers[i] = make([]byte, bufferSize) + } + for remainingSize > largeBlockSize*DataShardsCount { + err = encodeData(file, enc, processedSize, largeBlockSize, buffers, outputs) + if err != nil { + return fmt.Errorf("failed to encode large chunk data: %v", err) + } + remainingSize -= largeBlockSize * DataShardsCount + processedSize += largeBlockSize * DataShardsCount + } + for remainingSize > 0 { + encodeData(file, enc, processedSize, smallBlockSize, buffers, outputs) + if err != nil { + return fmt.Errorf("failed to encode small chunk data: %v", err) + } + remainingSize -= smallBlockSize * DataShardsCount + processedSize += smallBlockSize * DataShardsCount + } + return nil +} + +func readCompactMap(baseFileName string) (*needle_map.CompactMap, error) { + indexFile, err := os.OpenFile(baseFileName+".idx", os.O_RDONLY, 0644) + if err != nil { + return nil, fmt.Errorf("cannot read Volume Index %s.idx: %v", baseFileName, err) + } + defer indexFile.Close() + + cm := needle_map.NewCompactMap() + err = storage.WalkIndexFile(indexFile, func(key types.NeedleId, offset types.Offset, size uint32) error { + if !offset.IsZero() && size != types.TombstoneFileSize { + cm.Set(key, offset, size) + } else { + cm.Delete(key) + } + return nil + }) + return cm, err +} diff --git a/weed/storage/erasure_coding/ec_test.go b/weed/storage/erasure_coding/ec_test.go index d631471e9..625f4e9a6 100644 --- a/weed/storage/erasure_coding/ec_test.go +++ b/weed/storage/erasure_coding/ec_test.go @@ -7,7 +7,6 @@ import ( "os" "testing" - "github.com/chrislusf/seaweedfs/weed/storage" "github.com/chrislusf/seaweedfs/weed/storage/needle_map" "github.com/chrislusf/seaweedfs/weed/storage/types" "github.com/klauspost/reedsolomon" @@ -27,98 +26,20 @@ func TestEncodingDecoding(t *testing.T) { t.Logf("generateEcFiles: %v", err) } - err = writeSortedEcxFiles(baseFileName) + err = WriteSortedEcxFile(baseFileName) if err != nil { - t.Logf("writeSortedEcxFiles: %v", err) + t.Logf("WriteSortedEcxFile: %v", err) } err = validateFiles(baseFileName) if err != nil { - t.Logf("writeSortedEcxFiles: %v", err) + t.Logf("WriteSortedEcxFile: %v", err) } removeGeneratedFiles(baseFileName) } -func generateEcFiles(baseFileName string, bufferSize int, largeBlockSize int64, smallBlockSize int64) error { - file, err := os.OpenFile(baseFileName+".dat", os.O_RDONLY, 0) - if err != nil { - return fmt.Errorf("failed to open dat file: %v", err) - } - defer file.Close() - - fi, err := file.Stat() - if err != nil { - return fmt.Errorf("failed to stat dat file: %v", err) - } - err = encodeDatFile(fi.Size(), err, baseFileName, bufferSize, largeBlockSize, file, smallBlockSize) - if err != nil { - return fmt.Errorf("encodeDatFile: %v", err) - } - return nil -} - -func encodeDatFile(remainingSize int64, err error, baseFileName string, bufferSize int, largeBlockSize int64, file *os.File, smallBlockSize int64) error { - var processedSize int64 - enc, err := reedsolomon.New(DataShardsCount, ParityShardsCount) - if err != nil { - return fmt.Errorf("failed to create encoder: %v", err) - } - buffers := make([][]byte, DataShardsCount+ParityShardsCount) - outputs, err := openEcFiles(baseFileName, false) - defer closeEcFiles(outputs) - if err != nil { - return fmt.Errorf("failed to open dat file: %v", err) - } - for i, _ := range buffers { - buffers[i] = make([]byte, bufferSize) - } - for remainingSize > largeBlockSize*DataShardsCount { - err = encodeData(file, enc, processedSize, largeBlockSize, buffers, outputs) - if err != nil { - return fmt.Errorf("failed to encode large chunk data: %v", err) - } - remainingSize -= largeBlockSize * DataShardsCount - processedSize += largeBlockSize * DataShardsCount - } - for remainingSize > 0 { - encodeData(file, enc, processedSize, smallBlockSize, buffers, outputs) - if err != nil { - return fmt.Errorf("failed to encode small chunk data: %v", err) - } - remainingSize -= smallBlockSize * DataShardsCount - processedSize += smallBlockSize * DataShardsCount - } - return nil -} - -func writeSortedEcxFiles(baseFileName string) (e error) { - - cm, err := readCompactMap(baseFileName) - if err != nil { - return fmt.Errorf("readCompactMap: %v", err) - } - - ecxFile, err := os.OpenFile(baseFileName+".ecx", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - return fmt.Errorf("failed to open dat file: %v", err) - } - defer ecxFile.Close() - - err = cm.AscendingVisit(func(value needle_map.NeedleValue) error { - bytes := value.ToBytes() - _, writeErr := ecxFile.Write(bytes) - return writeErr - }) - - if err != nil { - return fmt.Errorf("failed to open dat file: %v", err) - } - - return nil -} - func validateFiles(baseFileName string) error { cm, err := readCompactMap(baseFileName) if err != nil { @@ -148,25 +69,6 @@ func validateFiles(baseFileName string) error { return nil } -func readCompactMap(baseFileName string) (*needle_map.CompactMap, error) { - indexFile, err := os.OpenFile(baseFileName+".idx", os.O_RDONLY, 0644) - if err != nil { - return nil, fmt.Errorf("cannot read Volume Index %s.idx: %v", baseFileName, err) - } - defer indexFile.Close() - - cm := needle_map.NewCompactMap() - err = storage.WalkIndexFile(indexFile, func(key types.NeedleId, offset types.Offset, size uint32) error { - if !offset.IsZero() && size != types.TombstoneFileSize { - cm.Set(key, offset, size) - } else { - cm.Delete(key) - } - return nil - }) - return cm, err -} - func assertSame(datFile *os.File, datSize int64, ecFiles []*os.File, offset types.Offset, size uint32) error { data, err := readDatFile(datFile, offset, size) @@ -288,7 +190,7 @@ func removeGeneratedFiles(baseFileName string) { fname := fmt.Sprintf("%s.ec%02d", baseFileName, i+1) os.Remove(fname) } - os.Remove(baseFileName+".ecx") + os.Remove(baseFileName + ".ecx") } func TestLocateData(t *testing.T) {