github.com/scottcagno/storage@v1.8.0/pkg/bio/_bio.go (about) 1 package bio 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 ) 8 9 // working toy impl --> https://go.dev/play/p/q0Ww_3QPNAe 10 // FINISHED PART --> https://go.dev/play/p/SkP9qNOdt7B 11 12 var ( 13 ErrInvalidSize = errors.New("bio: invalid size") 14 ErrInvalidOffset = errors.New("bio: invalid offset") 15 ErrDataTooBig = errors.New("bio: data too big") 16 ) 17 18 const ( 19 blockSize = 32 20 headerSize = 6 21 maxDataPerBlock = blockSize - headerSize 22 ) 23 24 const ( 25 blocksPerChunk = 16 26 chunkSize = blocksPerChunk * blockSize 27 maxDataPerChunk = blocksPerChunk * maxDataPerBlock 28 ) 29 30 const ( 31 chunksPerSegment = 15 32 segmentSize = chunksPerSegment * chunkSize 33 ) 34 35 const ( 36 blockMask = blockSize - 1 37 headerMask = headerSize - 1 38 chunkMask = chunkSize - 1 39 ) 40 41 const ( 42 statusEmpty = 0 43 statusActive = 1 44 statusDeleted = 2 45 statusOther = 3 46 ) 47 48 const ( 49 kindFull = 1 50 kindBeg = 2 51 kindMid = 3 52 kindEnd = 4 53 kindUnknown = 5 54 ) 55 56 type header struct { 57 status uint8 58 kind uint8 59 part uint8 60 parts uint8 61 length uint16 62 } 63 64 func (h *header) String() string { 65 return fmt.Sprintf("status=%d, kind=%d, part=%d, parts=%d, length=%d", 66 h.status, h.kind, h.part, h.parts, h.length) 67 } 68 69 func getKind(part, parts int) uint8 { 70 if parts == 1 { 71 return kindFull 72 } 73 if part == 1 { 74 return kindBeg 75 } 76 if part > 1 && part < parts { 77 return kindMid 78 } 79 if part == parts { 80 return kindEnd 81 } 82 return kindUnknown 83 } 84 85 func (h *header) Write(p []byte) (int, error) { 86 if p == nil || len(p) != 6 { 87 return -1, errors.New("bad size") 88 } 89 _ = p[5] 90 p[0] = h.status 91 p[1] = h.kind 92 p[2] = h.part 93 p[3] = h.parts 94 p[4] = byte(h.length) 95 p[5] = byte(h.length >> 8) 96 return len(p), nil 97 } 98 99 func encodeHeader(p []byte, h *header) (int, error) { 100 if p == nil || len(p) != 6 { 101 return -1, ErrInvalidSize 102 } 103 if h == nil { 104 // encode "zero value" header 105 h = new(header) 106 h.status = statusEmpty 107 h.kind = kindFull 108 h.part = 1 109 h.parts = 1 110 h.length = 0 111 } 112 _ = p[5] 113 p[0] = h.status 114 p[1] = h.kind 115 p[2] = h.part 116 p[3] = h.parts 117 p[4] = byte(h.length) 118 p[5] = byte(h.length >> 8) 119 return len(p), nil 120 } 121 122 func (h *header) WriteTo(w io.Writer) (int64, error) { 123 n, err := w.Write([]byte{ 124 h.status, 125 h.kind, 126 h.part, 127 h.parts, 128 byte(h.length), 129 byte(h.length >> 8), 130 }) 131 if err != nil { 132 return -1, err 133 } 134 return int64(n), nil 135 } 136 137 func (h *header) Read(p []byte) (int, error) { 138 if p == nil || len(p) != 6 { 139 return -1, errors.New("bad size") 140 } 141 _ = p[5] 142 h.status = p[0] 143 h.kind = p[1] 144 h.part = p[2] 145 h.parts = p[3] 146 h.length = uint16(p[4]) | uint16(p[5])<<8 147 return len(p), nil 148 } 149 150 func decodeHeader(p []byte, h *header) (int, error) { 151 if p == nil || len(p) != 6 { 152 return -1, ErrInvalidSize 153 } 154 _ = p[5] 155 h.status = p[0] 156 h.kind = p[1] 157 h.part = p[2] 158 h.parts = p[3] 159 h.length = uint16(p[4]) | uint16(p[5])<<8 160 return len(p), nil 161 } 162 163 func allocate(size int) []byte { 164 return calloc(align(size, size-1)) 165 } 166 167 func info(p *[]byte) { 168 if p == nil { 169 fmt.Println("ptr=nil, len=0, cap=0, data=nil") 170 } 171 fmt.Printf("ptr=%p, len=%d, cap=%d, data=%q\n", *p, len(*p), cap(*p), *p) 172 } 173 174 func longStr(s string, pre string, max int) string { 175 var ss string 176 for i := 0; i < len(s); i += max { 177 j := i + max 178 if j > len(s) { 179 j = len(s) 180 } 181 fmtr := fmt.Sprintf("%s| %%-%ds |\n", pre, max) 182 ss += fmt.Sprintf(fmtr, s[i:j]) 183 } 184 return ss 185 } 186 187 func divUp(dividend, divisor int) int { 188 // divide 189 res := dividend / divisor 190 // divided evenly 191 if (dividend % divisor) == 0 { 192 return res 193 } 194 // rounded down 195 if (divisor ^ dividend) >= 0 { 196 return res + 1 197 } 198 return res 199 } 200 201 func ChunkSliceIter(slice []int, chunkSize int, fn func(p []int) int) { 202 for beg := 0; beg < len(slice); beg += chunkSize { 203 end := beg + chunkSize 204 // necessary check to avoid slicing beyond 205 // slice capacity 206 if end > len(slice) { 207 end = len(slice) 208 } 209 n := fn(slice[beg:end]) 210 _ = n 211 } 212 } 213 214 // this impl does not continuously modify the slice, and uses iteration 215 func ChunkSliceV1(slice []int, chunkSize int) [][]int { 216 var chunks [][]int 217 for i := 0; i < len(slice); i += chunkSize { 218 end := i + chunkSize 219 // necessary check to avoid slicing beyond 220 // slice capacity 221 if end > len(slice) { 222 end = len(slice) 223 } 224 chunks = append(chunks, slice[i:end]) 225 } 226 return chunks 227 } 228 229 // this impl continuously modifies the slice and calls break eventually 230 func ChunkSliceV2(slice []int, chunkSize int) [][]int { 231 var chunks [][]int 232 for { 233 if len(slice) == 0 { 234 break 235 } 236 // necessary check to avoid slicing beyond 237 // slice capacity 238 if len(slice) < chunkSize { 239 chunkSize = len(slice) 240 } 241 chunks = append(chunks, slice[0:chunkSize]) 242 slice = slice[chunkSize:] 243 } 244 return chunks 245 } 246 247 func calcBlocks(size int) int { 248 size = align(size, blockMask) 249 return size / (blockSize - headerSize) 250 } 251 252 func align(size, mask int) int { 253 return (size + mask) &^ (mask) 254 } 255 256 func calloc(size int) []byte { 257 return make([]byte, size, size) 258 } 259 260 func malloc(size int) []byte { 261 return make([]byte, 0, size) 262 } 263 264 func clear(p *[]byte) (int, int) { 265 *p = (*p)[:0] 266 return len(*p), cap(*p) 267 } 268 269 func free(p *[]byte) { 270 *p = nil 271 }