github.com/m3db/m3@v1.5.0/src/m3ninx/index/segment/fst/encoding/docs/data.go (about) 1 // Copyright (c) 2018 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Softwarw. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package docs 22 23 import ( 24 "errors" 25 "fmt" 26 "io" 27 28 "github.com/m3db/m3/src/m3ninx/doc" 29 "github.com/m3db/m3/src/m3ninx/index/segment/fst/encoding" 30 ) 31 32 const initialDataEncoderLen = 1024 33 34 // DataWriter writes the data file for documents. 35 type DataWriter struct { 36 writer io.Writer 37 enc *encoding.Encoder 38 } 39 40 // NewDataWriter returns a new DataWriter. 41 func NewDataWriter(w io.Writer) *DataWriter { 42 return &DataWriter{ 43 writer: w, 44 enc: encoding.NewEncoder(initialDataEncoderLen), 45 } 46 } 47 48 func (w *DataWriter) Write(d doc.Metadata) (int, error) { 49 n := w.enc.PutBytes(d.ID) 50 n += w.enc.PutUvarint(uint64(len(d.Fields))) 51 for _, f := range d.Fields { 52 n += w.enc.PutBytes(f.Name) 53 n += w.enc.PutBytes(f.Value) 54 } 55 56 if err := w.write(); err != nil { 57 return 0, err 58 } 59 60 return n, nil 61 } 62 63 func (w *DataWriter) write() error { 64 b := w.enc.Bytes() 65 n, err := w.writer.Write(b) 66 if err != nil { 67 return err 68 } 69 if n < len(b) { 70 return io.ErrShortWrite 71 } 72 w.enc.Reset() 73 return nil 74 } 75 76 // Reset resets the DataWriter. 77 func (w *DataWriter) Reset(wr io.Writer) { 78 w.writer = wr 79 w.enc.Reset() 80 } 81 82 // DataReader is a reader for the data file for documents. 83 type DataReader struct { 84 data []byte 85 } 86 87 // NewDataReader returns a new DataReader. 88 func NewDataReader(data []byte) *DataReader { 89 return &DataReader{ 90 data: data, 91 } 92 } 93 94 func (r *DataReader) Read(offset uint64) (doc.Metadata, error) { 95 if offset >= uint64(len(r.data)) { 96 return doc.Metadata{}, fmt.Errorf("invalid offset: %v is past the end of the data file", offset) 97 } 98 dec := encoding.NewDecoder(r.data[int(offset):]) 99 id, err := dec.Bytes() 100 if err != nil { 101 return doc.Metadata{}, err 102 } 103 104 x, err := dec.Uvarint() 105 if err != nil { 106 return doc.Metadata{}, err 107 } 108 n := int(x) 109 110 d := doc.Metadata{ 111 ID: id, 112 Fields: make([]doc.Field, n), 113 } 114 115 for i := 0; i < n; i++ { 116 name, err := dec.Bytes() 117 if err != nil { 118 return doc.Metadata{}, err 119 } 120 val, err := dec.Bytes() 121 if err != nil { 122 return doc.Metadata{}, err 123 } 124 d.Fields[i] = doc.Field{ 125 Name: name, 126 Value: val, 127 } 128 } 129 130 return d, nil 131 } 132 133 // EncodedDataReader is a reader for the data file for encoded document metadata. 134 type EncodedDataReader struct { 135 data []byte 136 } 137 138 // NewEncodedDataReader returns a new EncodedDataReader. 139 func NewEncodedDataReader(data []byte) *EncodedDataReader { 140 return &EncodedDataReader{ 141 data: data, 142 } 143 } 144 145 // Read reads a doc.Encoded from a data stream starting at the specified offset. 146 func (e *EncodedDataReader) Read(offset uint64) (doc.Encoded, error) { 147 if offset >= uint64(len(e.data)) { 148 return doc.Encoded{}, fmt.Errorf( 149 "invalid offset: %v is past the end of the data file", offset, 150 ) 151 } 152 153 return doc.Encoded{ 154 Bytes: e.data[int(offset):], 155 }, nil 156 } 157 158 // EncodedDocumentReader is a reader for reading documents from encoded metadata. 159 type EncodedDocumentReader struct { 160 currFields []doc.Field 161 } 162 163 // NewEncodedDocumentReader returns a new EncodedDocumentReader. 164 func NewEncodedDocumentReader() *EncodedDocumentReader { 165 return &EncodedDocumentReader{} 166 } 167 168 // Read reads a doc.Metadata from a doc.Encoded. Returned doc.Metadata should be 169 // processed before calling Read again as the underlying array pointed to by the Fields 170 // slice will be updated. This approach avoids allocating a new slice with a new backing 171 // array for every document processed, unlike (*DataReader).Read 172 func (r *EncodedDocumentReader) Read(encoded doc.Encoded) (doc.Metadata, error) { 173 for i := range r.currFields { 174 r.currFields[i] = doc.Field{} 175 } 176 r.currFields = r.currFields[:0] 177 id, buf, err := encoding.ReadBytes(encoded.Bytes) 178 if err != nil { 179 return doc.Metadata{}, err 180 } 181 182 x, buf, err := encoding.ReadUvarint(buf) 183 if err != nil { 184 return doc.Metadata{}, err 185 } 186 n := int(x) 187 188 var name, val []byte 189 for i := 0; i < n; i++ { 190 name, buf, err = encoding.ReadBytes(buf) 191 if err != nil { 192 return doc.Metadata{}, err 193 } 194 val, buf, err = encoding.ReadBytes(buf) 195 if err != nil { 196 return doc.Metadata{}, err 197 } 198 r.currFields = append(r.currFields, doc.Field{ 199 Name: name, 200 Value: val, 201 }) 202 } 203 204 return doc.Metadata{ 205 ID: id, 206 Fields: r.currFields, 207 }, nil 208 } 209 210 // ReadEncodedDocumentID reads the document ID from the encoded document metadata. 211 func ReadEncodedDocumentID(encoded doc.Encoded) ([]byte, error) { 212 id, _, err := encoding.ReadBytes(encoded.Bytes) 213 return id, err 214 } 215 216 // MetadataFromDocument retrieves a doc.Metadata from a doc.Document. 217 func MetadataFromDocument(document doc.Document, reader *EncodedDocumentReader) (doc.Metadata, error) { 218 if d, ok := document.Metadata(); ok { 219 return d, nil 220 } 221 222 if e, ok := document.Encoded(); ok { 223 return reader.Read(e) 224 } 225 226 return doc.Metadata{}, errors.New("document does not contain metadata or encoded metadata") 227 } 228 229 // ReadIDFromDocument reads the document ID from the document. 230 func ReadIDFromDocument(document doc.Document) ([]byte, error) { 231 if d, ok := document.Metadata(); ok { 232 return d.ID, nil 233 } 234 235 if e, ok := document.Encoded(); ok { 236 return ReadEncodedDocumentID(e) 237 } 238 239 return nil, errors.New("document does not contain metadata or encoded metadata") 240 }