github.com/pingcap/badger@v1.5.1-0.20230103063557-828f39b09b6d/y/y.go (about) 1 /* 2 * Copyright 2017 Dgraph Labs, Inc. and Contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package y 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "fmt" 23 "hash/crc32" 24 "io" 25 "math" 26 "os" 27 "sync" 28 29 "github.com/pingcap/errors" 30 ) 31 32 // ErrEOF indicates an end of file when trying to read from a memory mapped file 33 // and encountering the end of slice. 34 var ErrEOF = errors.New("End of mapped region") 35 36 const ( 37 // Sync indicates that O_DSYNC should be set on the underlying file, 38 // ensuring that data writes do not return until the data is flushed 39 // to disk. 40 Sync = 1 << iota 41 // ReadOnly opens the underlying file on a read-only basis. 42 ReadOnly 43 ) 44 45 var ( 46 // This is O_DSYNC (datasync) on platforms that support it -- see file_unix.go 47 datasyncFileFlag = 0x0 48 49 // CastagnoliCrcTable is a CRC32 polynomial table 50 CastagnoliCrcTable = crc32.MakeTable(crc32.Castagnoli) 51 ) 52 53 // OpenExistingFile opens an existing file, errors if it doesn't exist. 54 func OpenExistingFile(filename string, flags uint32) (*os.File, error) { 55 openFlags := os.O_RDWR 56 if flags&ReadOnly != 0 { 57 openFlags = os.O_RDONLY 58 } 59 60 if flags&Sync != 0 { 61 openFlags |= datasyncFileFlag 62 } 63 return os.OpenFile(filename, openFlags, 0) 64 } 65 66 // CreateSyncedFile creates a new file (using O_EXCL), errors if it already existed. 67 func CreateSyncedFile(filename string, sync bool) (*os.File, error) { 68 flags := os.O_RDWR | os.O_CREATE | os.O_EXCL 69 if sync { 70 flags |= datasyncFileFlag 71 } 72 return os.OpenFile(filename, flags, 0666) 73 } 74 75 // OpenSyncedFile creates the file if one doesn't exist. 76 func OpenSyncedFile(filename string, sync bool) (*os.File, error) { 77 flags := os.O_RDWR | os.O_CREATE 78 if sync { 79 flags |= datasyncFileFlag 80 } 81 return os.OpenFile(filename, flags, 0666) 82 } 83 84 // OpenTruncFile opens the file with O_RDWR | O_CREATE | O_TRUNC 85 func OpenTruncFile(filename string, sync bool) (*os.File, error) { 86 flags := os.O_RDWR | os.O_CREATE | os.O_TRUNC 87 if sync { 88 flags |= datasyncFileFlag 89 } 90 return os.OpenFile(filename, flags, 0666) 91 } 92 93 // SafeCopy does append(a[:0], src...). 94 func SafeCopy(a []byte, src []byte) []byte { 95 return append(a[:0], src...) 96 } 97 98 // Copy copies a byte slice and returns the copied slice. 99 func Copy(a []byte) []byte { 100 b := make([]byte, len(a)) 101 copy(b, a) 102 return b 103 } 104 105 // KeyWithTs generates a new key by appending ts to key. 106 func KeyWithTs(key []byte, ts uint64) Key { 107 return Key{ 108 UserKey: key, 109 Version: ts, 110 } 111 } 112 113 // ParseKey parses the actual key from the key bytes. 114 func ParseKey(keyBytes []byte) Key { 115 if keyBytes == nil { 116 return Key{} 117 } 118 return Key{ 119 UserKey: keyBytes[:len(keyBytes)-8], 120 Version: math.MaxUint64 - binary.BigEndian.Uint64(keyBytes[len(keyBytes)-8:]), 121 } 122 } 123 124 // Slice holds a reusable buf, will reallocate if you request a larger size than ever before. 125 // One problem is with n distinct sizes in random order it'll reallocate log(n) times. 126 type Slice struct { 127 buf []byte 128 } 129 130 // Resize reuses the Slice's buffer (or makes a new one) and returns a slice in that buffer of 131 // length sz. 132 func (s *Slice) Resize(sz int) []byte { 133 if cap(s.buf) < sz { 134 s.buf = make([]byte, sz) 135 } 136 return s.buf[0:sz] 137 } 138 139 // Closer holds the two things we need to close a goroutine and wait for it to finish: a chan 140 // to tell the goroutine to shut down, and a WaitGroup with which to wait for it to finish shutting 141 // down. 142 type Closer struct { 143 closed chan struct{} 144 waiting sync.WaitGroup 145 } 146 147 // NewCloser constructs a new Closer, with an initial count on the WaitGroup. 148 func NewCloser(initial int) *Closer { 149 ret := &Closer{closed: make(chan struct{})} 150 ret.waiting.Add(initial) 151 return ret 152 } 153 154 // AddRunning Add()'s delta to the WaitGroup. 155 func (lc *Closer) AddRunning(delta int) { 156 lc.waiting.Add(delta) 157 } 158 159 // Signal signals the HasBeenClosed signal. 160 func (lc *Closer) Signal() { 161 close(lc.closed) 162 } 163 164 // HasBeenClosed gets signaled when Signal() is called. 165 func (lc *Closer) HasBeenClosed() <-chan struct{} { 166 return lc.closed 167 } 168 169 // Done calls Done() on the WaitGroup. 170 func (lc *Closer) Done() { 171 lc.waiting.Done() 172 } 173 174 // Wait waits on the WaitGroup. (It waits for NewCloser's initial value, AddRunning, and Done 175 // calls to balance out.) 176 func (lc *Closer) Wait() { 177 lc.waiting.Wait() 178 } 179 180 // SignalAndWait calls Signal(), then Wait(). 181 func (lc *Closer) SignalAndWait() { 182 lc.Signal() 183 lc.Wait() 184 } 185 186 // Key is the struct for user key with version. 187 type Key struct { 188 UserKey []byte 189 Version uint64 190 } 191 192 func (k Key) Compare(k2 Key) int { 193 cmp := bytes.Compare(k.UserKey, k2.UserKey) 194 if cmp != 0 { 195 return cmp 196 } 197 if k.Version > k2.Version { 198 // Greater version is considered smaller because we need to iterate keys from newer to older. 199 return -1 200 } else if k.Version < k2.Version { 201 return 1 202 } 203 return 0 204 } 205 206 func (k Key) Equal(k2 Key) bool { 207 if !bytes.Equal(k.UserKey, k2.UserKey) { 208 return false 209 } 210 return k.Version == k2.Version 211 } 212 213 func (k Key) IsEmpty() bool { 214 return len(k.UserKey) == 0 215 } 216 217 func (k *Key) Copy(k2 Key) { 218 k.UserKey = append(k.UserKey[:0], k2.UserKey...) 219 k.Version = k2.Version 220 } 221 222 func (k *Key) Reset() { 223 k.UserKey = k.UserKey[:0] 224 } 225 226 func (k Key) Len() int { 227 return len(k.UserKey) + 8 228 } 229 230 func (k Key) AppendTo(buf []byte) []byte { 231 buf = append(buf, k.UserKey...) 232 var uBuf [8]byte 233 binary.BigEndian.PutUint64(uBuf[:], math.MaxUint64-k.Version) 234 return append(buf, uBuf[:]...) 235 } 236 237 func (k Key) WriteTo(w io.Writer) error { 238 _, err := w.Write(k.UserKey) 239 if err != nil { 240 return err 241 } 242 var uBuf [8]byte 243 binary.BigEndian.PutUint64(uBuf[:], math.MaxUint64-k.Version) 244 _, err = w.Write(uBuf[:]) 245 return err 246 } 247 248 func (k Key) SameUserKey(k2 Key) bool { 249 return bytes.Equal(k.UserKey, k2.UserKey) 250 } 251 252 func (k Key) String() string { 253 return fmt.Sprintf("%x(%d)", k.UserKey, k.Version) 254 }