-
Notifications
You must be signed in to change notification settings - Fork 0
/
packet.go
185 lines (150 loc) · 3.87 KB
/
packet.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package stupid
import (
"bytes"
"io"
"github.com/utkarsh-pro/use/pkg/tlvrw"
)
const (
// IDTypeTLV is the type of the ID TLV
IDTypeTLV = byte(1)
// OpTypeTLV is the type of the operation TLV.
OpTypeTLV = byte(2)
// KeyTypeTLV is the type of the key TLV.
KeyTypeTLV = byte(3)
// ValTypeTLV is the type of the value TLV.
ValTypeTLV = byte(4)
)
// Packet is the basic unit of data transfer between the engine
// and the file system.
type Packet struct {
ID uint64
Op byte
Key []byte
Val []byte
vtlv *tlvrw.TLV
}
// reader is a packet reader
type reader struct {
// r is the underlying TLV reader
r *tlvrw.Reader
}
// writer is a packet writer
type writer struct {
// w is the underlying TLV writer
w io.Writer
}
// newreader returns a new packet reader
func newreader(r io.ReaderAt) *reader {
return &reader{
r: tlvrw.NewReader(r),
}
}
// newwriter returns a new packet writer
func newwriter(w io.Writer) *writer {
return &writer{
w: w,
}
}
// lread is a lazy reader which reads the packet
func (r *reader) lread(p *Packet) error {
// read the ID type TLV
idtlv := tlvrw.NewTLV(IDTypeTLV, nil)
if err := r.r.Read(idtlv); err != nil {
// EOF indicates that there are no more packets to read
if err == io.EOF {
return io.EOF
}
return err
}
p.ID = decodeid(idtlv.Val)
// read the operation type TLV
optlv := tlvrw.NewTLV(OpTypeTLV, nil)
if err := r.r.Read(optlv); err != nil {
if err == io.EOF {
// packets are set of 4 TLVs and we don't expect
// EOF on the second TLV read
return io.ErrUnexpectedEOF
}
return err
}
p.Op = optlv.Val[0]
// read the key type TLV
keytlv := tlvrw.NewTLV(KeyTypeTLV, nil)
if err := r.r.Read(keytlv); err != nil {
if err == io.EOF {
// packets are set of 4 TLVs and we don't expect
// EOF on the third TLV read
return io.ErrUnexpectedEOF
}
return err
}
p.Key = keytlv.Val
// read the value type TLV lazily
valtlv := tlvrw.NewTLV(ValTypeTLV, nil)
if err := r.r.ReadLazy(valtlv); err != nil {
if err == io.EOF {
// packets are set of 4 TLVs and we don't expect
// EOF on the fourth TLV read because TLV readers
// don't read beyond what is required.
return io.ErrUnexpectedEOF
}
return err
}
p.vtlv = valtlv
return nil
}
// fill fills the value type TLV with the value
func (r *reader) fill(p *Packet) error {
if p.vtlv == nil {
return nil
}
if err := r.r.Fill(p.vtlv); err != nil {
return err
}
p.Val = p.vtlv.Val
p.vtlv = nil
return nil
}
// pos returns the current position of the reader
func (r *reader) pos() int64 {
pos, _ := r.r.Seek(0, io.SeekCurrent)
return pos
}
// write writes the packet to the underlying writer
//
// write will copy the packet to a buffer and write the buffer
// to the underlying writer in one go. This is to ensure that the
// packet is written in one go and is not broken in between.
func (w *writer) write(p *Packet) error {
// get estimate size of the packet
sizeOfIDInBytes := uint32(8) // 8 bytes for uint64
sizeOfOpInBytes := uint32(1) // 1 byte for byte
sizeOfKeyInBytes := uint32(len(p.Key))
sizeOfValInBytes := uint32(len(p.Val))
size := sizeOfIDInBytes + sizeOfOpInBytes + sizeOfKeyInBytes + sizeOfValInBytes
// buffer data and write it in one go
buf := bytes.NewBuffer(make([]byte, 0, size))
// create a TLV writer
tw := tlvrw.NewWriter(buf)
// write the ID type TLV
if err := tw.Write(tlvrw.NewTLV(IDTypeTLV, encodeid(p.ID))); err != nil {
return err
}
// Write an operation type TLV
if err := tw.Write(tlvrw.NewTLV(OpTypeTLV, []byte{p.Op})); err != nil {
return err
}
// Write a key type TLV
if err := tw.Write(tlvrw.NewTLV(KeyTypeTLV, p.Key)); err != nil {
return err
}
// Write a value type TLV
if err := tw.Write(tlvrw.NewTLV(ValTypeTLV, p.Val)); err != nil {
return err
}
// write the buffer to the underlying writer
if _, err := w.w.Write(buf.Bytes()); err != nil {
return err
}
return nil
}