github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bithash/block2.go (about) 1 // Copyright 2021 The Bitalosdb author(hustxrb@163.com) and other contributors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package bithash 16 17 import ( 18 "encoding/binary" 19 "io" 20 "unsafe" 21 22 "github.com/zuoyebang/bitalosdb/internal/manual" 23 ) 24 25 const recordHeaderSize = 12 26 27 type block2Reader struct { 28 } 29 30 func (i *block2Reader) readRecordHeader(buf []byte) (ikeySize, valueSize uint32, fileNum FileNum) { 31 ikeySize = binary.LittleEndian.Uint32(buf[0:4]) 32 valueSize = binary.LittleEndian.Uint32(buf[4:8]) 33 fileNum = FileNum(binary.LittleEndian.Uint32(buf[8:12])) 34 return 35 } 36 37 func (i *block2Reader) readKV(buf []byte, ikeySize, valueSize uint32) (*InternalKey, []byte) { 38 ptr := unsafe.Pointer(&buf[0]) 39 40 key := getBytes(ptr, int(ikeySize)) 41 42 ptr = unsafe.Pointer(uintptr(ptr) + uintptr(ikeySize)) 43 value := getBytes(ptr, int(valueSize)) 44 45 var k InternalKey 46 if n := len(key) - 8; n >= 0 { 47 k.Trailer = binary.LittleEndian.Uint64(key[n:]) 48 k.UserKey = key[:n:n] 49 } else { 50 k.Trailer = uint64(InternalKeyKindInvalid) 51 } 52 53 return &k, value 54 } 55 56 func (i *block2Reader) readRecord(buf []byte) (*InternalKey, []byte, FileNum) { 57 ikeySize, valueSize, fileNum := i.readRecordHeader(buf) 58 recordLen := int(recordHeaderSize + ikeySize + valueSize) 59 if ikeySize == 0 || valueSize == 0 || len(buf) != recordLen { 60 return nil, nil, FileNum(0) 61 } 62 63 k, value := i.readKV(buf[recordHeaderSize:], ikeySize, valueSize) 64 return k, value, fileNum 65 } 66 67 type block2Writer struct { 68 buf []byte 69 wr io.Writer 70 } 71 72 func (w *block2Writer) set(key InternalKey, value []byte, fileNum FileNum) (int, error) { 73 keySize := key.Size() 74 preSize := keySize + recordHeaderSize 75 wrn := 0 76 77 if cap(w.buf) < preSize { 78 w.buf = make([]byte, 0, preSize*2) 79 } 80 81 w.buf = w.buf[:preSize] 82 binary.LittleEndian.PutUint32(w.buf[0:4], uint32(keySize)) 83 binary.LittleEndian.PutUint32(w.buf[4:8], uint32(len(value))) 84 binary.LittleEndian.PutUint32(w.buf[8:12], uint32(fileNum)) 85 86 key.Encode(w.buf[recordHeaderSize:]) 87 n, err := w.wr.Write(w.buf) 88 if err != nil { 89 return 0, err 90 } 91 wrn += n 92 93 n, err = w.wr.Write(value) 94 if err != nil { 95 return 0, err 96 } 97 wrn += n 98 99 w.buf = w.buf[:0] 100 return wrn, nil 101 } 102 103 func (w *block2Writer) setEmptyHeader() (int, error) { 104 var buf [recordHeaderSize]byte 105 for i := range buf { 106 buf[i] = 0 107 } 108 109 n, err := w.wr.Write(buf[:]) 110 if err != nil { 111 return 0, err 112 } 113 return n, nil 114 } 115 116 func getBytes(ptr unsafe.Pointer, length int) []byte { 117 return (*[manual.MaxArrayLen]byte)(ptr)[:length:length] 118 }