adds VolumeEcGenerateSlices, VolumeEcCopy

This commit is contained in:
Chris Lu 2019-05-20 00:53:17 -07:00
parent ae499fd5aa
commit fbbc74abb4
6 changed files with 508 additions and 236 deletions

View file

@ -47,6 +47,13 @@ service VolumeServer {
rpc VolumeTailReceiver (VolumeTailReceiverRequest) returns (VolumeTailReceiverResponse) { 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 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 { message ReadVolumeFileStatusRequest {
uint32 volume_id = 1; uint32 volume_id = 1;
} }

View file

@ -43,6 +43,10 @@ It has these top-level messages:
VolumeTailSenderResponse VolumeTailSenderResponse
VolumeTailReceiverRequest VolumeTailReceiverRequest
VolumeTailReceiverResponse VolumeTailReceiverResponse
VolumeEcGenerateSlicesRequest
VolumeEcGenerateSlicesResponse
VolumeEcCopyRequest
VolumeEcCopyResponse
ReadVolumeFileStatusRequest ReadVolumeFileStatusRequest
ReadVolumeFileStatusResponse ReadVolumeFileStatusResponse
DiskStatus DiskStatus
@ -766,6 +770,78 @@ func (m *VolumeTailReceiverResponse) String() string { return proto.C
func (*VolumeTailReceiverResponse) ProtoMessage() {} func (*VolumeTailReceiverResponse) ProtoMessage() {}
func (*VolumeTailReceiverResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{33} } 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 { type ReadVolumeFileStatusRequest struct {
VolumeId uint32 `protobuf:"varint,1,opt,name=volume_id,json=volumeId" json:"volume_id,omitempty"` 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) Reset() { *m = ReadVolumeFileStatusRequest{} }
func (m *ReadVolumeFileStatusRequest) String() string { return proto.CompactTextString(m) } func (m *ReadVolumeFileStatusRequest) String() string { return proto.CompactTextString(m) }
func (*ReadVolumeFileStatusRequest) ProtoMessage() {} 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 { func (m *ReadVolumeFileStatusRequest) GetVolumeId() uint32 {
if m != nil { if m != nil {
@ -796,7 +872,7 @@ type ReadVolumeFileStatusResponse struct {
func (m *ReadVolumeFileStatusResponse) Reset() { *m = ReadVolumeFileStatusResponse{} } func (m *ReadVolumeFileStatusResponse) Reset() { *m = ReadVolumeFileStatusResponse{} }
func (m *ReadVolumeFileStatusResponse) String() string { return proto.CompactTextString(m) } func (m *ReadVolumeFileStatusResponse) String() string { return proto.CompactTextString(m) }
func (*ReadVolumeFileStatusResponse) ProtoMessage() {} 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 { func (m *ReadVolumeFileStatusResponse) GetVolumeId() uint32 {
if m != nil { if m != nil {
@ -864,7 +940,7 @@ type DiskStatus struct {
func (m *DiskStatus) Reset() { *m = DiskStatus{} } func (m *DiskStatus) Reset() { *m = DiskStatus{} }
func (m *DiskStatus) String() string { return proto.CompactTextString(m) } func (m *DiskStatus) String() string { return proto.CompactTextString(m) }
func (*DiskStatus) ProtoMessage() {} 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 { func (m *DiskStatus) GetDir() string {
if m != nil { if m != nil {
@ -907,7 +983,7 @@ type MemStatus struct {
func (m *MemStatus) Reset() { *m = MemStatus{} } func (m *MemStatus) Reset() { *m = MemStatus{} }
func (m *MemStatus) String() string { return proto.CompactTextString(m) } func (m *MemStatus) String() string { return proto.CompactTextString(m) }
func (*MemStatus) ProtoMessage() {} 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 { func (m *MemStatus) GetGoroutines() int32 {
if m != nil { if m != nil {
@ -993,6 +1069,10 @@ func init() {
proto.RegisterType((*VolumeTailSenderResponse)(nil), "volume_server_pb.VolumeTailSenderResponse") proto.RegisterType((*VolumeTailSenderResponse)(nil), "volume_server_pb.VolumeTailSenderResponse")
proto.RegisterType((*VolumeTailReceiverRequest)(nil), "volume_server_pb.VolumeTailReceiverRequest") proto.RegisterType((*VolumeTailReceiverRequest)(nil), "volume_server_pb.VolumeTailReceiverRequest")
proto.RegisterType((*VolumeTailReceiverResponse)(nil), "volume_server_pb.VolumeTailReceiverResponse") 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((*ReadVolumeFileStatusRequest)(nil), "volume_server_pb.ReadVolumeFileStatusRequest")
proto.RegisterType((*ReadVolumeFileStatusResponse)(nil), "volume_server_pb.ReadVolumeFileStatusResponse") proto.RegisterType((*ReadVolumeFileStatusResponse)(nil), "volume_server_pb.ReadVolumeFileStatusResponse")
proto.RegisterType((*DiskStatus)(nil), "volume_server_pb.DiskStatus") 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) CopyFile(ctx context.Context, in *CopyFileRequest, opts ...grpc.CallOption) (VolumeServer_CopyFileClient, error)
VolumeTailSender(ctx context.Context, in *VolumeTailSenderRequest, opts ...grpc.CallOption) (VolumeServer_VolumeTailSenderClient, error) VolumeTailSender(ctx context.Context, in *VolumeTailSenderRequest, opts ...grpc.CallOption) (VolumeServer_VolumeTailSenderClient, error)
VolumeTailReceiver(ctx context.Context, in *VolumeTailReceiverRequest, opts ...grpc.CallOption) (*VolumeTailReceiverResponse, 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 { type volumeServerClient struct {
@ -1261,6 +1344,24 @@ func (c *volumeServerClient) VolumeTailReceiver(ctx context.Context, in *VolumeT
return out, nil 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 // Server API for VolumeServer service
type VolumeServerServer interface { type VolumeServerServer interface {
@ -1283,6 +1384,9 @@ type VolumeServerServer interface {
CopyFile(*CopyFileRequest, VolumeServer_CopyFileServer) error CopyFile(*CopyFileRequest, VolumeServer_CopyFileServer) error
VolumeTailSender(*VolumeTailSenderRequest, VolumeServer_VolumeTailSenderServer) error VolumeTailSender(*VolumeTailSenderRequest, VolumeServer_VolumeTailSenderServer) error
VolumeTailReceiver(context.Context, *VolumeTailReceiverRequest) (*VolumeTailReceiverResponse, 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) { 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) 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{ var _VolumeServer_serviceDesc = grpc.ServiceDesc{
ServiceName: "volume_server_pb.VolumeServer", ServiceName: "volume_server_pb.VolumeServer",
HandlerType: (*VolumeServerServer)(nil), HandlerType: (*VolumeServerServer)(nil),
@ -1664,6 +1804,14 @@ var _VolumeServer_serviceDesc = grpc.ServiceDesc{
MethodName: "VolumeTailReceiver", MethodName: "VolumeTailReceiver",
Handler: _VolumeServer_VolumeTailReceiver_Handler, Handler: _VolumeServer_VolumeTailReceiver_Handler,
}, },
{
MethodName: "VolumeEcGenerateSlices",
Handler: _VolumeServer_VolumeEcGenerateSlices_Handler,
},
{
MethodName: "VolumeEcCopy",
Handler: _VolumeServer_VolumeEcCopy_Handler,
},
}, },
Streams: []grpc.StreamDesc{ Streams: []grpc.StreamDesc{
{ {
@ -1688,95 +1836,101 @@ var _VolumeServer_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("volume_server.proto", fileDescriptor0) } func init() { proto.RegisterFile("volume_server.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 1436 bytes of a gzipped FileDescriptorProto // 1534 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xc4, 0x58, 0x4b, 0x73, 0xd4, 0xc6, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xc4, 0x58, 0xcb, 0x6f, 0xd4, 0xd6,
0x13, 0xb7, 0xd8, 0xb5, 0xbd, 0xee, 0x5d, 0x9b, 0x65, 0x6c, 0xf0, 0x7a, 0x79, 0x19, 0xc1, 0x1f, 0x1a, 0x8f, 0x99, 0xc9, 0xeb, 0x9b, 0x04, 0x86, 0x93, 0x90, 0x4c, 0x0c, 0x09, 0x83, 0xe1, 0xc2,
0x96, 0xc7, 0xdf, 0x10, 0xa8, 0x24, 0x24, 0x39, 0x24, 0x60, 0x92, 0x0a, 0x55, 0x01, 0xaa, 0x64, 0xf0, 0xb8, 0x81, 0x0b, 0xba, 0xf7, 0xd2, 0x87, 0xd4, 0x42, 0xa0, 0x6d, 0xa4, 0x02, 0x92, 0x03,
0xa0, 0x92, 0x4a, 0xaa, 0x54, 0x63, 0xa9, 0x8d, 0x55, 0xd6, 0x4a, 0x42, 0x33, 0x72, 0x70, 0x2a, 0xa8, 0x55, 0x2b, 0x59, 0x27, 0xf6, 0x17, 0x62, 0xc5, 0x63, 0x1b, 0xfb, 0x38, 0x4d, 0xaa, 0x76,
0xb7, 0xe4, 0x13, 0xe4, 0x2b, 0xe4, 0xc6, 0x21, 0xd7, 0x7c, 0xaa, 0x7c, 0x82, 0x5c, 0x52, 0xf3, 0xd5, 0xae, 0xba, 0xec, 0xb6, 0xcb, 0xee, 0xba, 0xe8, 0xb6, 0x7f, 0x55, 0xff, 0x82, 0x6e, 0xaa,
0x90, 0x76, 0xf5, 0xf2, 0x8a, 0x70, 0xc8, 0x6d, 0xb6, 0xa7, 0xdf, 0xea, 0xee, 0xf9, 0xf5, 0xc2, 0xf3, 0xb0, 0x67, 0xfc, 0xca, 0x98, 0x52, 0xa9, 0xbb, 0x33, 0xdf, 0xf9, 0x5e, 0xe7, 0xf3, 0xf7,
0xea, 0x61, 0xe8, 0x27, 0x63, 0xb4, 0x19, 0xc6, 0x87, 0x18, 0x6f, 0x45, 0x71, 0xc8, 0x43, 0xd2, 0xfa, 0x0d, 0x2c, 0x1d, 0x06, 0x5e, 0x32, 0x44, 0x2b, 0xc6, 0xe8, 0x10, 0xa3, 0xcd, 0x30, 0x0a,
0xcf, 0x11, 0xed, 0x68, 0xd7, 0xbc, 0x0d, 0xe4, 0x21, 0xe5, 0xce, 0xfe, 0x23, 0xf4, 0x91, 0xa3, 0x58, 0x40, 0xba, 0x39, 0xa2, 0x15, 0xee, 0x1a, 0xb7, 0x81, 0x3c, 0xa4, 0xcc, 0xde, 0x7f, 0x84,
0x85, 0xaf, 0x13, 0x64, 0x9c, 0x6c, 0x40, 0x67, 0xcf, 0xf3, 0xd1, 0xf6, 0x5c, 0x36, 0x30, 0x36, 0x1e, 0x32, 0x34, 0xf1, 0x75, 0x82, 0x31, 0x23, 0x6b, 0x30, 0xb7, 0xe7, 0x7a, 0x68, 0xb9, 0x4e,
0x5b, 0xa3, 0x25, 0x6b, 0x51, 0xfc, 0x7e, 0xec, 0x32, 0xf3, 0x19, 0xac, 0xe6, 0x04, 0x58, 0x14, 0xdc, 0xd3, 0xfa, 0xad, 0xc1, 0xbc, 0x39, 0xcb, 0x7f, 0x6f, 0x3b, 0xb1, 0xf1, 0x0c, 0x96, 0x72,
0x06, 0x0c, 0xc9, 0x7d, 0x58, 0x8c, 0x91, 0x25, 0x3e, 0x57, 0x02, 0xdd, 0xbb, 0x17, 0xb6, 0x8a, 0x02, 0x71, 0x18, 0xf8, 0x31, 0x92, 0xfb, 0x30, 0x1b, 0x61, 0x9c, 0x78, 0x4c, 0x0a, 0x74, 0xee,
0xb6, 0xb6, 0x32, 0x91, 0xc4, 0xe7, 0x56, 0xca, 0x6e, 0x7a, 0xd0, 0x9b, 0xbe, 0x20, 0xeb, 0xb0, 0x6e, 0x6c, 0x16, 0x6d, 0x6d, 0x66, 0x22, 0x89, 0xc7, 0xcc, 0x94, 0xdd, 0x70, 0x61, 0x61, 0xfc,
0xa8, 0x6d, 0x0f, 0x8c, 0x4d, 0x63, 0xb4, 0x64, 0x2d, 0x28, 0xd3, 0xe4, 0x0c, 0x2c, 0x30, 0x4e, 0x82, 0xac, 0xc2, 0xac, 0xb2, 0xdd, 0xd3, 0xfa, 0xda, 0x60, 0xde, 0x9c, 0x91, 0xa6, 0xc9, 0x0a,
0x79, 0xc2, 0x06, 0x27, 0x36, 0x8d, 0xd1, 0xbc, 0xa5, 0x7f, 0x91, 0x35, 0x98, 0xc7, 0x38, 0x0e, 0xcc, 0xc4, 0x8c, 0xb2, 0x24, 0xee, 0x9d, 0xea, 0x6b, 0x83, 0x69, 0x53, 0xfd, 0x22, 0xcb, 0x30,
0xe3, 0x41, 0x4b, 0xb2, 0xab, 0x1f, 0x84, 0x40, 0x9b, 0x79, 0x3f, 0xe1, 0xa0, 0xbd, 0x69, 0x8c, 0x8d, 0x51, 0x14, 0x44, 0xbd, 0x96, 0x60, 0x97, 0x3f, 0x08, 0x81, 0x76, 0xec, 0x7e, 0x8d, 0xbd,
0x96, 0x2d, 0x79, 0x36, 0x17, 0x61, 0xfe, 0xcb, 0x71, 0xc4, 0x8f, 0xcc, 0x8f, 0x61, 0xf0, 0x92, 0x76, 0x5f, 0x1b, 0x2c, 0x9a, 0xe2, 0x6c, 0xcc, 0xc2, 0xf4, 0xe3, 0x61, 0xc8, 0x8e, 0x8d, 0xff,
0x3a, 0x49, 0x32, 0x7e, 0x29, 0x7d, 0xdc, 0xde, 0x47, 0xe7, 0x20, 0x8d, 0xfd, 0x2c, 0x2c, 0x69, 0x43, 0xef, 0x25, 0xb5, 0x93, 0x64, 0xf8, 0x52, 0xf8, 0xb8, 0xb5, 0x8f, 0xf6, 0x41, 0xfa, 0xf6,
0xcf, 0xb5, 0x07, 0xcb, 0x56, 0x47, 0x11, 0x1e, 0xbb, 0xe6, 0x17, 0xb0, 0x51, 0x21, 0xa8, 0x73, 0xf3, 0x30, 0xaf, 0x3c, 0x57, 0x1e, 0x2c, 0x9a, 0x73, 0x92, 0xb0, 0xed, 0x18, 0x1f, 0xc2, 0x5a,
0x70, 0x19, 0x96, 0x5f, 0xd1, 0x78, 0x97, 0xbe, 0x42, 0x3b, 0xa6, 0xdc, 0x0b, 0xa5, 0xb4, 0x61, 0x85, 0xa0, 0x8a, 0xc1, 0x65, 0x58, 0x7c, 0x45, 0xa3, 0x5d, 0xfa, 0x0a, 0xad, 0x88, 0x32, 0x37,
0xf5, 0x34, 0xd1, 0x12, 0x34, 0xf3, 0x7b, 0x18, 0xe6, 0x34, 0x84, 0xe3, 0x88, 0x3a, 0xbc, 0x89, 0x10, 0xd2, 0x9a, 0xb9, 0xa0, 0x88, 0x26, 0xa7, 0x19, 0x5f, 0x80, 0x9e, 0xd3, 0x10, 0x0c, 0x43,
0x71, 0xb2, 0x09, 0xdd, 0x28, 0x46, 0xea, 0xfb, 0xa1, 0x43, 0x39, 0xca, 0x2c, 0xb4, 0xac, 0x69, 0x6a, 0xb3, 0x26, 0xc6, 0x49, 0x1f, 0x3a, 0x61, 0x84, 0xd4, 0xf3, 0x02, 0x9b, 0x32, 0x14, 0x51,
0x92, 0x79, 0x1e, 0xce, 0x56, 0x2a, 0x57, 0x0e, 0x9a, 0xf7, 0x0b, 0xde, 0x87, 0xe3, 0xb1, 0xd7, 0x68, 0x99, 0xe3, 0x24, 0x63, 0x1d, 0xce, 0x57, 0x2a, 0x97, 0x0e, 0x1a, 0xf7, 0x0b, 0xde, 0x07,
0xc8, 0xb4, 0x79, 0xae, 0xe4, 0xb5, 0x94, 0xd4, 0x7a, 0x3f, 0x29, 0xdc, 0xfa, 0x48, 0x83, 0x24, 0xc3, 0xa1, 0xdb, 0xc8, 0xb4, 0x71, 0xa1, 0xe4, 0xb5, 0x90, 0x54, 0x7a, 0xdf, 0x29, 0xdc, 0x7a,
0x6a, 0xa4, 0xb8, 0xe8, 0x71, 0x2a, 0x9a, 0x69, 0x5e, 0x57, 0xc5, 0xb1, 0x1d, 0xfa, 0x3e, 0x3a, 0x48, 0xfd, 0x24, 0x6c, 0xa4, 0xb8, 0xe8, 0x71, 0x2a, 0x9a, 0x69, 0x5e, 0x95, 0xc9, 0xb1, 0x15,
0xdc, 0x0b, 0x83, 0x54, 0xed, 0x05, 0x00, 0x27, 0x23, 0xea, 0x52, 0x99, 0xa2, 0x98, 0x43, 0x18, 0x78, 0x1e, 0xda, 0xcc, 0x0d, 0xfc, 0x54, 0xed, 0x06, 0x80, 0x9d, 0x11, 0x55, 0xaa, 0x8c, 0x51,
0x94, 0x45, 0xb5, 0xda, 0xb7, 0x06, 0x9c, 0x7e, 0xa0, 0x93, 0xa6, 0x0c, 0x37, 0xfa, 0x00, 0x79, 0x0c, 0x1d, 0x7a, 0x65, 0x51, 0xa5, 0xf6, 0x17, 0x0d, 0xce, 0x3d, 0x50, 0x41, 0x93, 0x86, 0x1b,
0x93, 0x27, 0x8a, 0x26, 0x8b, 0x1f, 0xa8, 0x55, 0xfa, 0x40, 0x82, 0x23, 0xc6, 0xc8, 0xf7, 0x1c, 0x7d, 0x80, 0xbc, 0xc9, 0x53, 0x45, 0x93, 0xc5, 0x0f, 0xd4, 0x2a, 0x7d, 0x20, 0xce, 0x11, 0x61,
0x2a, 0x55, 0xb4, 0xa5, 0x8a, 0x69, 0x12, 0xe9, 0x43, 0x8b, 0x73, 0x7f, 0x30, 0x2f, 0x6f, 0xc4, 0xe8, 0xb9, 0x36, 0x15, 0x2a, 0xda, 0x42, 0xc5, 0x38, 0x89, 0x74, 0xa1, 0xc5, 0x98, 0xd7, 0x9b,
0xd1, 0x1c, 0xc0, 0x99, 0xa2, 0xaf, 0x3a, 0x8c, 0x8f, 0x60, 0x5d, 0x51, 0x76, 0x8e, 0x02, 0x67, 0x16, 0x37, 0xfc, 0x68, 0xf4, 0x60, 0xa5, 0xe8, 0xab, 0x7a, 0xc6, 0xff, 0x60, 0x55, 0x52, 0x76,
0x47, 0x76, 0x43, 0xa3, 0xa4, 0xff, 0x6d, 0xc0, 0xa0, 0x2c, 0xa8, 0xab, 0xf8, 0x7d, 0x33, 0xf0, 0x8e, 0x7d, 0x7b, 0x47, 0x54, 0x43, 0xa3, 0xa0, 0xff, 0xa1, 0x41, 0xaf, 0x2c, 0xa8, 0xb2, 0xf8,
0xae, 0xf1, 0x91, 0x8b, 0xd0, 0xe5, 0xd4, 0xf3, 0xed, 0x70, 0x6f, 0x8f, 0x21, 0x1f, 0x2c, 0x6c, 0x6d, 0x23, 0xf0, 0xa6, 0xef, 0x23, 0x17, 0xa1, 0xc3, 0xa8, 0xeb, 0x59, 0xc1, 0xde, 0x5e, 0x8c,
0x1a, 0xa3, 0xb6, 0x05, 0x82, 0xf4, 0x4c, 0x52, 0xc8, 0x75, 0xe8, 0x3b, 0xaa, 0x92, 0xed, 0x18, 0xac, 0x37, 0xd3, 0xd7, 0x06, 0x6d, 0x13, 0x38, 0xe9, 0x99, 0xa0, 0x90, 0xeb, 0xd0, 0xb5, 0x65,
0x0f, 0x3d, 0x26, 0x34, 0x2f, 0x4a, 0xc7, 0x4e, 0x3a, 0x69, 0x85, 0x2b, 0x32, 0x31, 0x61, 0xd9, 0x26, 0x5b, 0x11, 0x1e, 0xba, 0x31, 0xd7, 0x3c, 0x2b, 0x1c, 0x3b, 0x63, 0xa7, 0x19, 0x2e, 0xc9,
0x73, 0xdf, 0xd8, 0x72, 0x80, 0xc8, 0xf6, 0xef, 0x48, 0x6d, 0x5d, 0xcf, 0x7d, 0xf3, 0x95, 0xe7, 0xc4, 0x80, 0x45, 0xd7, 0x39, 0xb2, 0x44, 0x03, 0x11, 0xe5, 0x3f, 0x27, 0xb4, 0x75, 0x5c, 0xe7,
0xe3, 0x8e, 0x98, 0x02, 0x2f, 0xe1, 0x9c, 0x0a, 0xfe, 0x71, 0xe0, 0xc4, 0x38, 0xc6, 0x80, 0x53, 0xe8, 0x23, 0xd7, 0xc3, 0x1d, 0xde, 0x05, 0x5e, 0xc2, 0x05, 0xf9, 0xf8, 0x6d, 0xdf, 0x8e, 0x70,
0x7f, 0x3b, 0x8c, 0x8e, 0x1a, 0x95, 0xc0, 0x06, 0x74, 0x98, 0x17, 0x38, 0x68, 0x07, 0x6a, 0x0c, 0x88, 0x3e, 0xa3, 0xde, 0x56, 0x10, 0x1e, 0x37, 0x4a, 0x81, 0x35, 0x98, 0x8b, 0x5d, 0xdf, 0x46,
0xb5, 0xad, 0x45, 0xf9, 0xfb, 0x29, 0x33, 0x1f, 0xc2, 0xf9, 0x1a, 0xbd, 0x3a, 0xb3, 0x97, 0xa0, 0xcb, 0x97, 0x6d, 0xa8, 0x6d, 0xce, 0x8a, 0xdf, 0x4f, 0x63, 0xe3, 0x21, 0xac, 0xd7, 0xe8, 0x55,
0x27, 0x1d, 0x73, 0xc2, 0x80, 0x63, 0xc0, 0xa5, 0xee, 0x9e, 0xd5, 0x15, 0xb4, 0x6d, 0x45, 0x32, 0x91, 0xbd, 0x04, 0x0b, 0xc2, 0x31, 0x3b, 0xf0, 0x19, 0xfa, 0x4c, 0xe8, 0x5e, 0x30, 0x3b, 0x9c,
0x3f, 0x00, 0xa2, 0x74, 0x3c, 0x09, 0x93, 0xa0, 0x59, 0x6b, 0x9e, 0x86, 0xd5, 0x9c, 0x88, 0xae, 0xb6, 0x25, 0x49, 0xc6, 0x7f, 0x80, 0x48, 0x1d, 0x4f, 0x82, 0xc4, 0x6f, 0x56, 0x9a, 0xe7, 0x60,
0x8d, 0x7b, 0xb0, 0xa6, 0xc8, 0x2f, 0x82, 0x71, 0x63, 0x5d, 0xeb, 0x70, 0xba, 0x20, 0xa4, 0xb5, 0x29, 0x27, 0xa2, 0x72, 0xe3, 0x1e, 0x2c, 0x4b, 0xf2, 0x0b, 0x7f, 0xd8, 0x58, 0xd7, 0x2a, 0x9c,
0xdd, 0x4d, 0x8d, 0xe4, 0xdf, 0x89, 0x63, 0x95, 0x9d, 0x49, 0x3d, 0xc8, 0x3f, 0x15, 0xe6, 0x1f, 0x2b, 0x08, 0x29, 0x6d, 0x77, 0x53, 0x23, 0xf9, 0x39, 0x71, 0xa2, 0xb2, 0x95, 0xd4, 0x83, 0xfc,
0x06, 0x9c, 0x4a, 0xc7, 0x48, 0xc3, 0xac, 0xbf, 0x63, 0xd9, 0xb5, 0x6a, 0xcb, 0xae, 0x3d, 0x29, 0xa8, 0x30, 0x7e, 0xd5, 0xe0, 0x6c, 0xda, 0x46, 0x1a, 0x46, 0xfd, 0x0d, 0xd3, 0xae, 0x55, 0x9b,
0xbb, 0x11, 0xf4, 0x59, 0x98, 0xc4, 0x0e, 0xda, 0x2e, 0xe5, 0xd4, 0x0e, 0x42, 0x17, 0x75, 0x55, 0x76, 0xed, 0x51, 0xda, 0x0d, 0xa0, 0x1b, 0x07, 0x49, 0x64, 0xa3, 0xe5, 0x50, 0x46, 0x2d, 0x3f,
0xae, 0x28, 0xfa, 0x23, 0xca, 0xe9, 0xd3, 0xd0, 0x45, 0xf3, 0xf3, 0xf4, 0xa3, 0xe4, 0xbe, 0xe6, 0x70, 0x50, 0x65, 0xe5, 0x69, 0x49, 0x7f, 0x44, 0x19, 0x7d, 0x1a, 0x38, 0x68, 0x7c, 0x90, 0x7e,
0x75, 0x38, 0xe5, 0x53, 0xc6, 0x6d, 0x1a, 0x45, 0x18, 0xb8, 0x36, 0xe5, 0xa2, 0x24, 0x0c, 0x59, 0x94, 0xdc, 0xd7, 0xbc, 0x0e, 0x67, 0x3d, 0x1a, 0x33, 0x8b, 0x86, 0x21, 0xfa, 0x8e, 0x45, 0x19,
0x12, 0x2b, 0xe2, 0xe2, 0x81, 0xa4, 0x3f, 0xe0, 0x4f, 0x99, 0xf9, 0x9b, 0x01, 0x27, 0x85, 0xac, 0x4f, 0x09, 0x4d, 0xa4, 0xc4, 0x69, 0x7e, 0xf1, 0x40, 0xd0, 0x1f, 0xb0, 0xa7, 0xb1, 0xf1, 0xa3,
0x28, 0xc1, 0x46, 0xf1, 0xf6, 0xa1, 0x85, 0x6f, 0xb8, 0x0e, 0x54, 0x1c, 0xc9, 0x6d, 0x58, 0xd5, 0x06, 0x67, 0xb8, 0x2c, 0x4f, 0xc1, 0x46, 0xef, 0xed, 0x42, 0x0b, 0x8f, 0x98, 0x7a, 0x28, 0x3f,
0xb5, 0xee, 0x85, 0xc1, 0xa4, 0x0d, 0x5a, 0x52, 0x90, 0x4c, 0xae, 0xb2, 0x4e, 0xb8, 0x08, 0x5d, 0x92, 0xdb, 0xb0, 0xa4, 0x72, 0xdd, 0x0d, 0xfc, 0x51, 0x19, 0xb4, 0x84, 0x20, 0x19, 0x5d, 0x65,
0xc6, 0xc3, 0x28, 0xed, 0xaa, 0xb6, 0xea, 0x2a, 0x41, 0x52, 0x5d, 0x65, 0x7e, 0x08, 0xfd, 0x89, 0x95, 0x70, 0x11, 0x3a, 0x31, 0x0b, 0xc2, 0xb4, 0xaa, 0xda, 0xb2, 0xaa, 0x38, 0x49, 0x56, 0x95,
0x4f, 0xcd, 0x2b, 0xf4, 0x17, 0x23, 0x1d, 0x3a, 0xcf, 0xa9, 0xe7, 0xef, 0x60, 0xe0, 0x62, 0xfc, 0xf1, 0x5f, 0xe8, 0x8e, 0x7c, 0x6a, 0x9e, 0xa1, 0xdf, 0x69, 0x69, 0xd3, 0x79, 0x4e, 0x5d, 0x6f,
0x9e, 0x9d, 0x43, 0xee, 0xc0, 0x9a, 0xe7, 0xfa, 0x68, 0x73, 0x6f, 0x8c, 0x61, 0xc2, 0x6d, 0x86, 0x07, 0x7d, 0x07, 0xa3, 0xb7, 0xac, 0x1c, 0x72, 0x07, 0x96, 0x5d, 0xc7, 0x43, 0x8b, 0xb9, 0x43,
0x4e, 0x18, 0xb8, 0x2c, 0x8d, 0x4e, 0xdc, 0x3d, 0x57, 0x57, 0x3b, 0xea, 0xc6, 0xfc, 0x35, 0x9b, 0x0c, 0x12, 0x66, 0xc5, 0x68, 0x07, 0xbe, 0x13, 0xa7, 0xaf, 0xe3, 0x77, 0xcf, 0xe5, 0xd5, 0x8e,
0x60, 0xd3, 0x5e, 0x4c, 0xde, 0xe1, 0x00, 0x51, 0x28, 0xdc, 0x47, 0xea, 0x62, 0xac, 0xc3, 0xe8, 0xbc, 0x31, 0xbe, 0xcf, 0x3a, 0xd8, 0xb8, 0x17, 0xa3, 0x39, 0xec, 0x23, 0x72, 0x85, 0xfb, 0x48,
0x29, 0xe2, 0xd7, 0x92, 0x26, 0xf2, 0xa3, 0x99, 0x76, 0x43, 0xf7, 0x48, 0x7a, 0xd4, 0xb3, 0x40, 0x1d, 0x8c, 0xd4, 0x33, 0x16, 0x24, 0xf1, 0x13, 0x41, 0xe3, 0xf1, 0x51, 0x4c, 0xbb, 0x81, 0x73,
0x91, 0x1e, 0x86, 0xee, 0x91, 0x1c, 0x25, 0xcc, 0x96, 0x9f, 0xd8, 0xd9, 0x4f, 0x82, 0x03, 0xe9, 0x2c, 0x3c, 0x5a, 0x30, 0x41, 0x92, 0x1e, 0x06, 0xce, 0xb1, 0x68, 0x25, 0xb1, 0x25, 0x3e, 0xb1,
0x4d, 0xc7, 0xea, 0x7a, 0xec, 0x1b, 0xca, 0xf8, 0xb6, 0x20, 0x99, 0x7f, 0x1a, 0xb0, 0x31, 0x71, 0xbd, 0x9f, 0xf8, 0x07, 0xc2, 0x9b, 0x39, 0xb3, 0xe3, 0xc6, 0x9f, 0xd2, 0x98, 0x6d, 0x71, 0x92,
0xc3, 0x42, 0x07, 0xbd, 0xc3, 0xff, 0x20, 0x1d, 0x42, 0x42, 0xd7, 0x72, 0x0e, 0x74, 0xe9, 0x72, 0xf1, 0x9b, 0x06, 0x6b, 0x23, 0x37, 0x4c, 0xb4, 0xd1, 0x3d, 0xfc, 0x07, 0xc2, 0xc1, 0x25, 0x54,
0x27, 0xea, 0x4e, 0x4f, 0x7c, 0x79, 0x23, 0x1f, 0xf4, 0x0a, 0xc7, 0x75, 0x8b, 0x7e, 0x0a, 0x67, 0x2e, 0xe7, 0x96, 0x2e, 0x95, 0xee, 0x44, 0xde, 0xa9, 0x8e, 0x2f, 0x6e, 0xc4, 0x40, 0xaf, 0x70,
0x2d, 0xa4, 0xae, 0xe2, 0x90, 0x83, 0xb3, 0xf9, 0xe3, 0xf2, 0xd7, 0x09, 0x38, 0x57, 0x2d, 0xdc, 0x5c, 0x95, 0xe8, 0xfb, 0x69, 0x2b, 0x7b, 0x6c, 0x7f, 0x8c, 0x3e, 0x46, 0x94, 0xe1, 0x8e, 0xe7,
0xe4, 0x81, 0xf9, 0x0c, 0x86, 0xd9, 0x00, 0x17, 0xf1, 0x33, 0x4e, 0xc7, 0x51, 0x96, 0x01, 0x95, 0xda, 0xd8, 0x6c, 0xbc, 0xf4, 0x61, 0xa3, 0x4e, 0x5a, 0xe9, 0xff, 0x49, 0x4b, 0xfb, 0xc9, 0x63,
0xa8, 0x75, 0x3d, 0xcd, 0x9f, 0xa7, 0xf7, 0x69, 0x1a, 0x4a, 0xd3, 0xbf, 0x55, 0x9a, 0xfe, 0xc2, 0xfb, 0x6f, 0x6b, 0x02, 0xeb, 0x00, 0x68, 0x5b, 0xae, 0xef, 0xe0, 0x11, 0xf2, 0x60, 0xb5, 0x06,
0x80, 0x4b, 0x79, 0x9d, 0x01, 0xd5, 0x26, 0xeb, 0x2e, 0xe5, 0x75, 0x06, 0x32, 0x61, 0x69, 0x60, 0x8b, 0xe6, 0x3c, 0xda, 0xdb, 0x92, 0xf0, 0x06, 0xf5, 0x9e, 0x35, 0xae, 0xd4, 0x39, 0xe5, 0xf5,
0x5e, 0x19, 0xd0, 0xfc, 0xd2, 0xc0, 0x79, 0x00, 0xdd, 0x43, 0x49, 0x90, 0xbe, 0x66, 0x4b, 0xaa, 0xbb, 0x70, 0xde, 0x44, 0xea, 0xc8, 0x3b, 0x31, 0x4e, 0x9a, 0x8f, 0xdc, 0xdf, 0x4f, 0xc1, 0x85,
0x83, 0x92, 0xa0, 0xb6, 0x91, 0x17, 0x6b, 0x1b, 0x39, 0x3f, 0xfb, 0x3a, 0x25, 0x9c, 0xf3, 0x2d, 0x6a, 0xe1, 0x26, 0x63, 0xf7, 0x3d, 0xd0, 0xb3, 0xb1, 0xc6, 0xb3, 0x22, 0x66, 0x74, 0x18, 0x66,
0xc0, 0x23, 0x8f, 0x1d, 0xa8, 0x24, 0x8b, 0xc9, 0xe1, 0x7a, 0xb1, 0x86, 0x43, 0xe2, 0x28, 0x28, 0x79, 0x21, 0xd3, 0x67, 0x55, 0xcd, 0xb8, 0xe7, 0xe9, 0x7d, 0x9a, 0x1c, 0xa5, 0x99, 0xd8, 0x2a,
0xd4, 0xf7, 0x75, 0xea, 0xc4, 0x51, 0x40, 0xe3, 0x84, 0xa1, 0xab, 0xb3, 0x23, 0xcf, 0x82, 0xb6, 0xcd, 0x44, 0x6e, 0xc0, 0xa1, 0xac, 0xce, 0x80, 0x6c, 0x1e, 0xab, 0x0e, 0x65, 0x75, 0x06, 0x32,
0x17, 0x23, 0xea, 0x04, 0xc8, 0xb3, 0xf9, 0xbb, 0x01, 0x4b, 0x4f, 0x70, 0xac, 0x35, 0x5f, 0x00, 0x61, 0x61, 0x60, 0x5a, 0x1a, 0x50, 0xfc, 0xc2, 0xc0, 0x3a, 0x80, 0xea, 0x2c, 0x89, 0x9f, 0xce,
0x78, 0x15, 0xc6, 0x61, 0xc2, 0xbd, 0x00, 0xd5, 0xa0, 0x9b, 0xb7, 0xa6, 0x28, 0xff, 0xde, 0x8e, 0xf8, 0x79, 0xd9, 0x57, 0x12, 0xbf, 0xb6, 0xbd, 0xcd, 0xd6, 0xb6, 0xb7, 0x7c, 0x32, 0xcc, 0x95,
0x84, 0xea, 0xe8, 0xef, 0xe9, 0x64, 0xca, 0xb3, 0xa0, 0xed, 0x23, 0x8d, 0x74, 0xfe, 0xe4, 0x59, 0xb6, 0xbf, 0xcf, 0x00, 0x1e, 0xb9, 0xf1, 0x81, 0x0c, 0x32, 0xef, 0xa7, 0x8e, 0x1b, 0xa9, 0x25,
0x00, 0x7d, 0xc6, 0xa9, 0x73, 0x20, 0x93, 0xd5, 0xb6, 0xd4, 0x8f, 0xbb, 0x6f, 0x57, 0xa0, 0x37, 0x91, 0x1f, 0x39, 0x85, 0x7a, 0x9e, 0x0a, 0x1d, 0x3f, 0x72, 0xc0, 0x90, 0xc4, 0xe8, 0xa8, 0xe8,
0x5d, 0xda, 0xe4, 0x07, 0xe8, 0x4e, 0x6d, 0x28, 0xe4, 0x4a, 0x79, 0x11, 0x29, 0x6f, 0x3c, 0xc3, 0x88, 0x33, 0xa7, 0xed, 0x45, 0x88, 0x2a, 0x00, 0xe2, 0x6c, 0xfc, 0xac, 0xc1, 0xfc, 0x13, 0x1c,
0xff, 0xcd, 0xe0, 0xd2, 0x8d, 0x31, 0x47, 0x02, 0x38, 0x55, 0xda, 0x00, 0xc8, 0x8d, 0xb2, 0x74, 0x2a, 0xcd, 0x1b, 0x00, 0xaf, 0x82, 0x28, 0x48, 0x98, 0xeb, 0xa3, 0x6c, 0xff, 0xd3, 0xe6, 0x18,
0xdd, 0x7e, 0x31, 0xbc, 0xd9, 0x88, 0x37, 0xb3, 0xc7, 0x61, 0xb5, 0x02, 0xd2, 0x93, 0x5b, 0x33, 0xe5, 0xaf, 0xdb, 0x11, 0x00, 0x06, 0xbd, 0x3d, 0x15, 0x4c, 0x71, 0xe6, 0xb4, 0x7d, 0xa4, 0xa1,
0xb4, 0xe4, 0xd6, 0x8a, 0xe1, 0xff, 0x1b, 0x72, 0x67, 0x56, 0x5f, 0x03, 0x29, 0xe3, 0x7d, 0x72, 0x8a, 0x9f, 0x38, 0x73, 0xf8, 0x13, 0x33, 0x6a, 0x1f, 0x88, 0x60, 0xb5, 0x4d, 0xf9, 0xe3, 0xee,
0x73, 0xa6, 0x9a, 0xc9, 0x3e, 0x31, 0xbc, 0xd5, 0x8c, 0xb9, 0x36, 0x50, 0xb5, 0x09, 0xcc, 0x0c, 0x0f, 0x5d, 0x58, 0x18, 0x2f, 0x78, 0xf2, 0x25, 0x74, 0xc6, 0x70, 0x1b, 0xb9, 0x52, 0x86, 0x67,
0x34, 0xb7, 0x6b, 0xcc, 0x0c, 0xb4, 0xb0, 0x5e, 0xcc, 0x91, 0x03, 0xe8, 0x17, 0xb7, 0x04, 0x72, 0x65, 0x1c, 0xa8, 0xff, 0x6b, 0x02, 0x97, 0x2a, 0x8c, 0x29, 0xe2, 0xc3, 0xd9, 0x12, 0x2e, 0x22,
0xbd, 0x6e, 0x75, 0x2d, 0x2d, 0x21, 0xc3, 0x1b, 0x4d, 0x58, 0x33, 0x63, 0x08, 0x2b, 0x79, 0x24, 0x37, 0xca, 0xd2, 0x75, 0xa8, 0x4b, 0xbf, 0xd9, 0x88, 0x37, 0xb3, 0xc7, 0x60, 0xa9, 0x02, 0xe8,
0x4f, 0xae, 0x95, 0xe5, 0x2b, 0xf7, 0x92, 0xe1, 0x68, 0x36, 0xe3, 0x74, 0x4c, 0x45, 0x74, 0x5f, 0x90, 0x5b, 0x13, 0xb4, 0xe4, 0xc0, 0x96, 0xfe, 0xef, 0x86, 0xdc, 0x99, 0xd5, 0xd7, 0x40, 0xca,
0x15, 0x53, 0xcd, 0xea, 0x50, 0x15, 0x53, 0xdd, 0xb2, 0x60, 0xce, 0x91, 0x9f, 0x53, 0xc8, 0x58, 0x28, 0x88, 0xdc, 0x9c, 0xa8, 0x66, 0x84, 0xb2, 0xf4, 0x5b, 0xcd, 0x98, 0x6b, 0x1f, 0x2a, 0xf1,
0x40, 0xbd, 0x64, 0xab, 0x4e, 0x4d, 0x35, 0xec, 0x1e, 0xde, 0x6e, 0xcc, 0x9f, 0xda, 0xbe, 0x63, 0xd1, 0xc4, 0x87, 0xe6, 0x10, 0xd8, 0xc4, 0x87, 0x16, 0x40, 0xd7, 0x14, 0x39, 0x80, 0x6e, 0x11,
0x88, 0x5e, 0x9f, 0x02, 0xbf, 0x55, 0xbd, 0x5e, 0x86, 0xd3, 0x55, 0xbd, 0x5e, 0x85, 0xa0, 0xe7, 0x3b, 0x91, 0xeb, 0x75, 0x80, 0xbe, 0x04, 0xcd, 0xf4, 0x1b, 0x4d, 0x58, 0x33, 0x63, 0x08, 0xa7,
0xc8, 0x2e, 0x2c, 0xe7, 0xe0, 0x30, 0xb9, 0x5a, 0x27, 0x99, 0x07, 0xd9, 0xc3, 0x6b, 0x33, 0xf9, 0xf3, 0xf8, 0x86, 0x5c, 0x2b, 0xcb, 0x57, 0xa2, 0x35, 0x7d, 0x30, 0x99, 0x71, 0xfc, 0x4d, 0x45,
0x32, 0x1b, 0x76, 0x3a, 0xbd, 0xf4, 0xb8, 0xaa, 0x75, 0x2e, 0x3f, 0xaf, 0xae, 0xce, 0x62, 0xcb, 0xcc, 0x53, 0xf5, 0xa6, 0x1a, 0x40, 0x55, 0xf5, 0xa6, 0x3a, 0x08, 0x65, 0x4c, 0x91, 0x6f, 0xd2,
0x0c, 0x7c, 0x07, 0x30, 0x41, 0xaf, 0xe4, 0x72, 0x9d, 0xdc, 0xf4, 0xa7, 0xb8, 0x72, 0x3c, 0x53, 0x45, 0xba, 0x80, 0x05, 0xc8, 0x66, 0x9d, 0x9a, 0x6a, 0x30, 0xa2, 0xdf, 0x6e, 0xcc, 0x9f, 0xda,
0xa6, 0xfa, 0x47, 0x58, 0xab, 0x7a, 0xe9, 0x49, 0x45, 0x17, 0x1e, 0x03, 0x27, 0x86, 0x5b, 0x4d, 0xbe, 0xa3, 0xf1, 0x5a, 0x1f, 0x83, 0x04, 0x55, 0xb5, 0x5e, 0x06, 0x19, 0x55, 0xb5, 0x5e, 0x85,
0xd9, 0x33, 0xc3, 0x2f, 0xa0, 0x93, 0x62, 0x57, 0x72, 0xa9, 0x2c, 0x5d, 0xc0, 0xda, 0x43, 0xf3, 0x2b, 0xa6, 0xc8, 0x2e, 0x2c, 0xe6, 0x40, 0x02, 0xb9, 0x5a, 0x27, 0x99, 0x87, 0x1e, 0xfa, 0xb5,
0x38, 0x96, 0xa9, 0x6a, 0x1a, 0xa7, 0x8d, 0x33, 0x01, 0x95, 0xf5, 0x8d, 0x53, 0x82, 0xbf, 0xf5, 0x89, 0x7c, 0x99, 0x0d, 0x2b, 0xed, 0x5e, 0xaa, 0x5d, 0xd5, 0x3a, 0x97, 0xef, 0x57, 0x57, 0x27,
0x8d, 0x53, 0xc6, 0xa8, 0xd2, 0xdc, 0xeb, 0x74, 0xaf, 0x98, 0xc6, 0x60, 0x95, 0x43, 0xb6, 0x0e, 0xb1, 0x65, 0x06, 0x3e, 0x07, 0x18, 0xed, 0xf4, 0xe4, 0x72, 0x9d, 0xdc, 0xf8, 0xa7, 0xb8, 0x72,
0x62, 0x56, 0x0e, 0xd9, 0x7a, 0x58, 0x37, 0xb7, 0xbb, 0x20, 0xff, 0x07, 0xbc, 0xf7, 0x4f, 0x00, 0x32, 0x53, 0xa6, 0xfa, 0x2b, 0x58, 0xae, 0x9a, 0xf4, 0xa4, 0xa2, 0x0a, 0x4f, 0x58, 0x27, 0xf4,
0x00, 0x00, 0xff, 0xff, 0x5d, 0xbf, 0x08, 0x06, 0x1e, 0x14, 0x00, 0x00, 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,
} }

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"math"
"os" "os"
"time" "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)) volumeFileName = storage.VolumeFileName(volFileInfoResp.Collection, location.Directory, int(req.VolumeId))
// println("source:", volFileInfoResp.String()) // println("source:", volFileInfoResp.String())
// copy ecx file
copyFileClient, err := client.CopyFile(ctx, &volume_server_pb.CopyFileRequest{ if err:=vs.doCopyFile(ctx, client, req.VolumeId, volFileInfoResp.CompactionRevision, volFileInfoResp.IdxFileSize, volumeFileName, ".idx"); err!=nil{
VolumeId: req.VolumeId, return err
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" if err:=vs.doCopyFile(ctx, client, req.VolumeId, volFileInfoResp.CompactionRevision, volFileInfoResp.DatFileSize, volumeFileName, ".dat"); err!=nil{
err = writeToFile(copyFileClient, idxFileName, util.NewWriteThrottler(vs.compactionBytePerSecond)) return err
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)
}
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)
} }
return nil return nil
@ -109,6 +86,28 @@ func (vs *VolumeServer) VolumeCopy(ctx context.Context, req *volume_server_pb.Vo
}, err }, 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 only check the the differ of the file size
todo: maybe should check the received count and deleted count of the volume 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 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 { func (vs *VolumeServer) CopyFile(req *volume_server_pb.CopyFileRequest, stream volume_server_pb.VolumeServer_CopyFileServer) error {
v := vs.store.GetVolume(needle.VolumeId(req.VolumeId)) 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) 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) return fmt.Errorf("volume %d is compacted", req.VolumeId)
} }

View file

@ -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
}

View file

@ -6,6 +6,9 @@ import (
"os" "os"
"github.com/chrislusf/seaweedfs/weed/glog" "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" "github.com/klauspost/reedsolomon"
) )
@ -16,11 +19,66 @@ const (
ErasureCodingSmallBlockSize = 1024 * 1024 // 1MB 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 { func encodeData(file *os.File, enc reedsolomon.Encoder, startOffset, blockSize int64, buffers [][]byte, outputs []*os.File) error {
bufferSize := int64(len(buffers[0])) bufferSize := int64(len(buffers[0]))
batchCount := blockSize/bufferSize batchCount := blockSize / bufferSize
if blockSize%bufferSize!=0 { if blockSize%bufferSize != 0 {
glog.Fatalf("unexpected block size %d buffer size %d", blockSize, bufferSize) 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 return nil
} }
func openEcFiles(baseFileName string, forRead bool) (files []*os.File, err error){ func openEcFiles(baseFileName string, forRead bool) (files []*os.File, err error) {
for i := 0; i< DataShardsCount+ParityShardsCount; i++{ for i := 0; i < DataShardsCount+ParityShardsCount; i++ {
fname := fmt.Sprintf("%s.ec%02d", baseFileName, i+1) fname := baseFileName + ToExt(i+1)
openOption := os.O_TRUNC|os.O_CREATE|os.O_WRONLY openOption := os.O_TRUNC | os.O_CREATE | os.O_WRONLY
if forRead { if forRead {
openOption = os.O_RDONLY openOption = os.O_RDONLY
} }
@ -50,15 +108,14 @@ func openEcFiles(baseFileName string, forRead bool) (files []*os.File, err error
return return
} }
func closeEcFiles(files []*os.File){ func closeEcFiles(files []*os.File) {
for _, f := range files{ for _, f := range files {
if f != nil { if f != nil {
f.Close() f.Close()
} }
} }
} }
func encodeDataOneBatch(file *os.File, enc reedsolomon.Encoder, startOffset, blockSize int64, buffers [][]byte, outputs []*os.File) error { func encodeDataOneBatch(file *os.File, enc reedsolomon.Encoder, startOffset, blockSize int64, buffers [][]byte, outputs []*os.File) error {
// read data into buffers // read data into buffers
@ -90,3 +147,56 @@ func encodeDataOneBatch(file *os.File, enc reedsolomon.Encoder, startOffset, blo
return nil 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
}

View file

@ -7,7 +7,6 @@ import (
"os" "os"
"testing" "testing"
"github.com/chrislusf/seaweedfs/weed/storage"
"github.com/chrislusf/seaweedfs/weed/storage/needle_map" "github.com/chrislusf/seaweedfs/weed/storage/needle_map"
"github.com/chrislusf/seaweedfs/weed/storage/types" "github.com/chrislusf/seaweedfs/weed/storage/types"
"github.com/klauspost/reedsolomon" "github.com/klauspost/reedsolomon"
@ -27,98 +26,20 @@ func TestEncodingDecoding(t *testing.T) {
t.Logf("generateEcFiles: %v", err) t.Logf("generateEcFiles: %v", err)
} }
err = writeSortedEcxFiles(baseFileName) err = WriteSortedEcxFile(baseFileName)
if err != nil { if err != nil {
t.Logf("writeSortedEcxFiles: %v", err) t.Logf("WriteSortedEcxFile: %v", err)
} }
err = validateFiles(baseFileName) err = validateFiles(baseFileName)
if err != nil { if err != nil {
t.Logf("writeSortedEcxFiles: %v", err) t.Logf("WriteSortedEcxFile: %v", err)
} }
removeGeneratedFiles(baseFileName) 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 { func validateFiles(baseFileName string) error {
cm, err := readCompactMap(baseFileName) cm, err := readCompactMap(baseFileName)
if err != nil { if err != nil {
@ -148,25 +69,6 @@ func validateFiles(baseFileName string) error {
return nil 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 { func assertSame(datFile *os.File, datSize int64, ecFiles []*os.File, offset types.Offset, size uint32) error {
data, err := readDatFile(datFile, offset, size) data, err := readDatFile(datFile, offset, size)
@ -288,7 +190,7 @@ func removeGeneratedFiles(baseFileName string) {
fname := fmt.Sprintf("%s.ec%02d", baseFileName, i+1) fname := fmt.Sprintf("%s.ec%02d", baseFileName, i+1)
os.Remove(fname) os.Remove(fname)
} }
os.Remove(baseFileName+".ecx") os.Remove(baseFileName + ".ecx")
} }
func TestLocateData(t *testing.T) { func TestLocateData(t *testing.T) {