github.com/coyove/sdss@v0.0.0-20231129015646-c2ec58cca6a2/contrib/bitmap/utils.go (about) 1 package bitmap 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "math/bits" 8 "os" 9 "time" 10 11 "github.com/coyove/sdss/contrib/clock" 12 ) 13 14 type Values struct { 15 Oneof []uint64 16 Major []uint64 17 Exact []uint64 18 } 19 20 type meterWriter struct { 21 io.Writer 22 size int 23 } 24 25 func (m *meterWriter) Close() error { 26 return nil 27 } 28 29 func (m *meterWriter) Write(p []byte) (int, error) { 30 n, err := m.Writer.Write(p) 31 m.size += n 32 return n, err 33 } 34 35 func h16(v uint32, ts int64) (out [4]uint32) { 36 const mask = 0xffffffff 37 out[0] = combinehash(v, uint32(ts)) & mask 38 out[1] = combinehash(v, out[0]) & mask 39 out[2] = combinehash(v, out[1]) & mask 40 out[3] = combinehash(v, out[2]) & mask 41 return 42 } 43 44 func icmp(a, b int64) int { 45 if a > b { 46 return 1 47 } 48 if a < b { 49 return -1 50 } 51 return 0 52 } 53 54 func h32(index uint32, hash uint32) (out uint32) { 55 return index<<17 | hash&0x1ffff 56 } 57 58 func combinehash(k1, seed uint32) uint32 { 59 h1 := seed 60 61 k1 *= 0xcc9e2d51 62 k1 = bits.RotateLeft32(k1, 15) 63 k1 *= 0x1b873593 64 65 h1 ^= k1 66 h1 = bits.RotateLeft32(h1, 13) 67 h1 = h1*4 + h1 + 0xe6546b64 68 69 h1 ^= uint32(4) 70 71 h1 ^= h1 >> 16 72 h1 *= 0x85ebca6b 73 h1 ^= h1 >> 13 74 h1 *= 0xc2b2ae35 75 h1 ^= h1 >> 16 76 77 return h1 78 } 79 80 type KeyIdScore struct { 81 Key Key 82 Id int64 83 Score int 84 } 85 86 type JoinMetrics struct { 87 BaseStart int64 88 Start int64 89 Desc bool 90 Values Values 91 FastElapsed time.Duration 92 Elapsed time.Duration 93 Slots [slotNum]struct { 94 Scans, Hits int 95 Elapsed time.Duration 96 } 97 } 98 99 func (jm JoinMetrics) String() string { 100 dir := "asc" 101 if jm.Desc { 102 dir = "desc" 103 } 104 x := fmt.Sprintf("join map [%d] start at %d (%s) in %vus", 105 jm.BaseStart, jm.Start, dir, jm.Elapsed.Microseconds()) 106 x += fmt.Sprintf("\n\tinput: oneof=%d, major=%d (min=%d), exact=%d", 107 len(jm.Values.Oneof), len(jm.Values.Major), jm.Values.majorScore(), len(jm.Values.Exact)) 108 x += fmt.Sprintf("\n\tfast lookup: %vus", jm.FastElapsed.Microseconds()) 109 110 c := 0 111 for i := len(jm.Slots) - 1; i >= 0; i-- { 112 s := jm.Slots[i] 113 if s.Scans > 0 { 114 x += fmt.Sprintf("\n\tsubrange [%02d]: %4dus, %d out of %d", 115 i, s.Elapsed.Microseconds(), s.Hits, s.Scans) 116 if s.Hits == 0 { 117 x += " (NO HITS)" 118 } 119 c++ 120 } 121 } 122 if c == 0 { 123 x += " (NO HITS)" 124 } 125 return x 126 } 127 128 func (b *Range) Save(path string, compress bool) (int, error) { 129 b.mfmu.Lock() 130 defer b.mfmu.Unlock() 131 132 bakpath := fmt.Sprintf("%s.%d.mtfbak", path, clock.Unix()) 133 134 f, err := os.Create(bakpath) 135 if err != nil { 136 return 0, err 137 } 138 sz, err := b.Marshal(f, compress) 139 f.Close() 140 if err != nil { 141 return 0, err 142 } 143 144 if err := os.Remove(path); err != nil { 145 if !os.IsNotExist(err) { 146 return 0, err 147 } 148 } 149 return sz, os.Rename(bakpath, path) 150 } 151 152 func Load(path string) (*Range, error) { 153 f, err := os.Open(path) 154 if err != nil { 155 if os.IsNotExist(err) { 156 return nil, nil 157 } 158 return nil, err 159 } 160 defer f.Close() 161 return Unmarshal(f) 162 } 163 164 type bitmap1024 [fastSlotNum / 64]uint64 165 166 func (b *bitmap1024) add(index uint16) { // [0, fastSlotNum) 167 (*b)[index/64] |= 1 << (index % 64) 168 } 169 170 func (b *bitmap1024) contains(index uint16) bool { 171 return (*b)[index/64]&(1<<(index%64)) > 0 172 } 173 174 func (b *bitmap1024) iterate(f func(uint16) bool) { 175 for si, s := range *b { 176 for i := 0; i < 64; i++ { 177 if s&(1<<i) > 0 { 178 if !f(uint16(si*64 + i)) { 179 return 180 } 181 } 182 } 183 } 184 } 185 186 func (b *bitmap1024) and(b2 *bitmap1024) { 187 for i := range *b { 188 (*b)[i] &= (*b2)[i] 189 } 190 } 191 192 func (b *bitmap1024) or(b2 *bitmap1024) { 193 for i := range *b { 194 (*b)[i] |= (*b2)[i] 195 } 196 } 197 198 func (b bitmap1024) String() string { 199 buf := bytes.NewBufferString("{fast bitmap") 200 for i := 0; i < fastSlotNum; i++ { 201 if b.contains(uint16(i)) { 202 fmt.Fprintf(buf, " %d", i) 203 } 204 } 205 buf.WriteString("}") 206 return buf.String() 207 } 208 209 func (vs *Values) majorScore() int { 210 s := len(vs.Major) 211 if s <= 2 { 212 return s 213 } 214 if s <= 4 { 215 return s - 1 216 } 217 return s * 4 / 5 218 } 219 220 func (v *Values) Clean() { 221 m := map[uint64]byte{} 222 223 add := func(a []uint64, typ byte) { 224 for _, v := range a { 225 m[v] = typ 226 } 227 } 228 remove := func(a []uint64, typ byte) []uint64 { 229 for i := len(a) - 1; i >= 0; i-- { 230 if m[a[i]] != typ { 231 a = append(a[:i], a[i+1:]...) 232 } 233 } 234 return a 235 } 236 237 add(v.Oneof, 'o') 238 add(v.Major, 'm') 239 add(v.Exact, 'e') 240 241 v.Oneof = remove(v.Oneof, 'o') 242 v.Major = remove(v.Major, 'm') 243 v.Exact = remove(v.Exact, 'e') 244 }