github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/segment/writer/segwriter.go (about) 1 /* 2 Copyright 2023. 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 writer 18 19 import ( 20 "bufio" 21 "bytes" 22 "encoding/json" 23 "errors" 24 "fmt" 25 "math" 26 "math/rand" 27 "os" 28 "strconv" 29 "strings" 30 "sync" 31 "time" 32 33 "github.com/cespare/xxhash" 34 "github.com/klauspost/compress/zstd" 35 "github.com/siglens/siglens/pkg/blob" 36 "github.com/siglens/siglens/pkg/common/fileutils" 37 "github.com/siglens/siglens/pkg/segment/pqmr" 38 "github.com/siglens/siglens/pkg/segment/structs" 39 . "github.com/siglens/siglens/pkg/segment/utils" 40 "github.com/siglens/siglens/pkg/segment/writer/metrics" 41 "github.com/siglens/siglens/pkg/segment/writer/suffix" 42 "github.com/siglens/siglens/pkg/utils" 43 44 log "github.com/sirupsen/logrus" 45 46 "github.com/bits-and-blooms/bloom/v3" 47 "github.com/siglens/siglens/pkg/config" 48 "github.com/siglens/siglens/pkg/instrumentation" 49 bbp "github.com/valyala/bytebufferpool" 50 ) 51 52 // Throttle the number of indexes to help prevent excessive memory usage. 53 const maxAllowedSegStores = 1000 54 55 // global map 56 var allSegStores = map[string]*SegStore{} 57 var allSegStoresLock sync.RWMutex = sync.RWMutex{} 58 var maxSegFileSize uint64 59 60 var KibanaInternalBaseDir string 61 62 var smrLock sync.Mutex = sync.Mutex{} 63 var localSegmetaFname string 64 65 // Create a writer that caches compressors. 66 // For this operation type we supply a nil Reader. 67 var encoder, _ = zstd.NewWriter(nil) 68 var decoder, _ = zstd.NewReader(nil) 69 70 func InitKibanaInternalData() { 71 KibanaInternalBaseDir = config.GetDataPath() + "common/kibanainternaldata/" 72 err := os.MkdirAll(KibanaInternalBaseDir, 0764) 73 if err != nil { 74 log.Error(err) 75 } 76 } 77 78 type SegfileRotateInfo struct { 79 FinalName string 80 TimeRotated uint64 81 } 82 83 type ColWip struct { 84 cbufidx uint32 // end index of buffer, only cbuf[:cbufidx] exists 85 cstartidx uint32 // start index of last record, so cbuf[cstartidx:cbufidx] is the encoded last record 86 cbuf [WIP_SIZE]byte // in progress bytes 87 csgFname string // file name of csg file 88 deMap map[string][]uint16 // dictWordKey ==> recordNums that match this key 89 deCount uint16 // keeps track of cardinality count for this COL_WIP 90 } 91 92 type RangeIndex struct { 93 Ranges map[string]*structs.Numbers 94 } 95 96 type BloomIndex struct { 97 Bf *bloom.BloomFilter 98 uniqueWordCount uint32 99 HistoricalCount []uint32 100 } 101 102 type RolledRecs struct { 103 lastRecNum uint16 104 MatchedRes *pqmr.PQMatchResults 105 } 106 107 // All WIP BLOCK related info will be stored here 108 109 type WipBlock struct { 110 columnBlooms map[string]*BloomIndex 111 blockSummary structs.BlockSummary 112 columnRangeIndexes map[string]*RangeIndex 113 colWips map[string]*ColWip 114 columnsInBlock map[string]bool 115 pqMatches map[string]*pqmr.PQMatchResults 116 maxIdx uint32 117 blockTs []uint64 118 tomRollup map[uint64]*RolledRecs // top-of-minute rollup 119 tohRollup map[uint64]*RolledRecs // top-of-hour rollup 120 todRollup map[uint64]*RolledRecs // top-of-day rollup 121 bb *bbp.ByteBuffer // byte buffer pool for HLL byte inserts 122 } 123 124 // returns in memory size of a single wip block 125 func (wp *WipBlock) getSize() uint64 { 126 size := uint64(0) 127 for _, v := range wp.columnBlooms { 128 size += uint64(v.Bf.Cap() / 8) 129 } 130 size += wp.blockSummary.GetSize() 131 size += uint64(24 * len(wp.columnRangeIndexes)) 132 size += uint64(WIP_SIZE * len(wp.colWips)) 133 for _, v := range wp.pqMatches { 134 size += v.GetInMemSize() 135 } 136 return size 137 } 138 139 func HostnameDir() { 140 var sb strings.Builder 141 sb.WriteString(config.GetDataPath()) 142 sb.WriteString("ingestnodes/") 143 sb.WriteString(config.GetHostID()) 144 hostnamesDir := sb.String() 145 err := os.MkdirAll(hostnamesDir, 0764) 146 if err != nil { 147 log.Error(err) 148 } 149 } 150 151 // returns the total size used by AllSegStores 152 func GetInMemorySize() uint64 { 153 allSegStoresLock.RLock() 154 defer allSegStoresLock.RUnlock() 155 156 totalSize := uint64(0) 157 for _, s := range allSegStores { 158 totalSize += s.wipBlock.getSize() 159 } 160 161 totalSize += metrics.GetTotalEncodedSize() 162 163 return uint64(math.Ceil(ConvertFloatBytesToMB(float64(totalSize) * float64(1.10)))) 164 } 165 166 func InitWriterNode() { 167 // one time initialization 168 AllUnrotatedSegmentInfo = make(map[string]*UnrotatedSegmentInfo) 169 RecentlyRotatedSegmentFiles = make(map[string]*SegfileRotateInfo) 170 metrics.InitMetricsSegStore() 171 172 initSmr() 173 174 go timeBasedWIPFlushToFile() 175 go timeBasedRotateSegment() 176 go cleanRecentlyRotatedInfo() 177 go timeBasedUploadIngestNodeDir() 178 HostnameDir() 179 InitKibanaInternalData() 180 } 181 182 func initSmr() { 183 184 localSegmetaFname = GetLocalSegmetaFName() 185 186 fd, err := os.OpenFile(localSegmetaFname, os.O_RDONLY, 0666) 187 if err != nil { 188 if errors.Is(err, os.ErrNotExist) { 189 // for first time during bootup this will occur 190 _, err := os.OpenFile(localSegmetaFname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) 191 if err != nil { 192 log.Errorf("initSmr: failed to open a new filename=%v: err=%v", localSegmetaFname, err) 193 return 194 } 195 } 196 return 197 } 198 fd.Close() 199 } 200 201 // TODO: this should be pushed based & we should have checks in uploadingestnode function to prevent uploading unupdated files. 202 func timeBasedUploadIngestNodeDir() { 203 for { 204 time.Sleep(UPLOAD_INGESTNODE_DIR) 205 err := blob.UploadIngestNodeDir() 206 if err != nil { 207 log.Errorf("timeBasedUploadIngestNodeDir: failed to upload ingestnode dir: err=%v", err) 208 } 209 } 210 } 211 212 func cleanRecentlyRotatedInternal() { 213 currTime := utils.GetCurrentTimeInMs() 214 recentlyRotatedSegmentFilesLock.Lock() 215 defer recentlyRotatedSegmentFilesLock.Unlock() 216 for key, value := range RecentlyRotatedSegmentFiles { 217 if currTime-value.TimeRotated > STALE_RECENTLY_ROTATED_ENTRY_MS { 218 delete(RecentlyRotatedSegmentFiles, key) 219 } 220 } 221 } 222 223 func cleanRecentlyRotatedInfo() { 224 for { 225 sleepDuration := time.Millisecond * STALE_RECENTLY_ROTATED_ENTRY_MS 226 time.Sleep(sleepDuration) 227 cleanRecentlyRotatedInternal() 228 } 229 } 230 231 // This is the only function that needs to be exported from this package, since this is the only 232 // place where we play with the locks 233 234 func AddEntryToInMemBuf(streamid string, rawJson []byte, ts_millis uint64, 235 indexName string, bytesReceived uint64, flush bool, signalType SIGNAL_TYPE, orgid uint64) error { 236 237 segstore, err := getSegStore(streamid, ts_millis, indexName, orgid) 238 if err != nil { 239 log.Errorf("AddEntryToInMemBuf, getSegstore err=%v", err) 240 return err 241 } 242 243 segstore.lock.Lock() 244 defer segstore.lock.Unlock() 245 if segstore.wipBlock.maxIdx+MAX_RECORD_SIZE >= WIP_SIZE || 246 segstore.wipBlock.blockSummary.RecCount >= MAX_RECS_PER_WIP { 247 err = segstore.AppendWipToSegfile(streamid, false, false, false) 248 if err != nil { 249 log.Errorf("AddEntryToInMemBuf: failed to append segkey=%v, err=%v", segstore.SegmentKey, err) 250 return err 251 } 252 instrumentation.IncrementInt64Counter(instrumentation.WIP_BUFFER_FLUSH_COUNT, 1) 253 } 254 255 segstore.adjustEarliestLatestTimes(ts_millis) 256 segstore.wipBlock.adjustEarliestLatestTimes(ts_millis) 257 err = segstore.WritePackedRecord(rawJson, ts_millis, signalType) 258 if err != nil { 259 return err 260 } 261 segstore.BytesReceivedCount += bytesReceived 262 263 if flush { 264 err = segstore.AppendWipToSegfile(streamid, false, false, false) 265 if err != nil { 266 log.Errorf("AddEntryToInMemBuf: failed to append during flush segkey=%v, err=%v", segstore.SegmentKey, err) 267 return err 268 } 269 } 270 return nil 271 } 272 273 func AddTimeSeriesEntryToInMemBuf(rawJson []byte, signalType SIGNAL_TYPE, orgid uint64) error { 274 switch signalType { 275 case SIGNAL_METRICS_OTSDB: 276 tagsHolder := metrics.GetTagsHolder() 277 mName, dp, ts, err := metrics.ExtractOTSDBPayload(rawJson, tagsHolder) 278 if err != nil { 279 metrics.ReturnTagsHolder(tagsHolder) 280 return err 281 } 282 err = metrics.EncodeDatapoint(mName, tagsHolder, dp, ts, uint64(len(rawJson)), orgid) 283 if err != nil { 284 metrics.ReturnTagsHolder(tagsHolder) 285 return err 286 } 287 metrics.ReturnTagsHolder(tagsHolder) 288 case SIGNAL_METRICS_INFLUX: 289 tagsHolder := metrics.GetTagsHolder() 290 mName, dp, ts, err := metrics.ExtractInfluxPayload(rawJson, tagsHolder) 291 if err != nil { 292 metrics.ReturnTagsHolder(tagsHolder) 293 return err 294 } 295 err = metrics.EncodeDatapoint(mName, tagsHolder, dp, ts, uint64(len(rawJson)), orgid) 296 if err != nil { 297 metrics.ReturnTagsHolder(tagsHolder) 298 return err 299 } 300 metrics.ReturnTagsHolder(tagsHolder) 301 default: 302 return fmt.Errorf("unknown signal type %+v", signalType) 303 } 304 305 return nil 306 } 307 308 // This function is used when os.Interrupt is caught 309 // meta files need to be updated to not lose range/bloom/file path info on node failure 310 func ForcedFlushToSegfile() { 311 log.Warnf("Flushing %+v segment files on server exit", len(allSegStores)) 312 allSegStoresLock.Lock() 313 for streamid, segstore := range allSegStores { 314 segstore.lock.Lock() 315 err := segstore.AppendWipToSegfile(streamid, true, false, false) 316 if err != nil { 317 log.Errorf("ForcedFlushToSegfile: failed to append err=%v", err) 318 } 319 log.Warnf("Flushing segment file for streamid %s server exit", streamid) 320 segstore.lock.Unlock() 321 delete(allSegStores, streamid) 322 } 323 allSegStoresLock.Unlock() 324 } 325 326 func updateValuesFromConfig() { 327 maxSegFileSize = *config.GetMaxSegFileSize() 328 } 329 330 func timeBasedWIPFlushToFile() { 331 for { 332 sleepDuration := time.Duration(config.GetSegFlushIntervalSecs()) * time.Second 333 time.Sleep(sleepDuration) 334 FlushWipBufferToFile(&sleepDuration) 335 } 336 } 337 338 func rotateSegmentOnTime() { 339 segRotateDuration := time.Duration(SEGMENT_ROTATE_DURATION_SECONDS) * time.Second 340 allSegStoresLock.RLock() 341 wg := sync.WaitGroup{} 342 for sid, ss := range allSegStores { 343 344 if ss.firstTime { 345 rnm := rand.Intn(SEGMENT_ROTATE_DURATION_SECONDS) + 60 346 segRotateDuration = time.Duration(rnm) * time.Second 347 } else { 348 segRotateDuration = time.Duration(SEGMENT_ROTATE_DURATION_SECONDS) * time.Second 349 } 350 351 if time.Since(ss.timeCreated) < segRotateDuration { 352 continue 353 } 354 wg.Add(1) 355 go func(streamid string, segstore *SegStore) { 356 defer wg.Done() 357 segstore.lock.Lock() 358 segstore.firstTime = false 359 err := segstore.AppendWipToSegfile(streamid, false, false, true) 360 if err != nil { 361 log.Errorf("rotateSegmentOnTime: failed to append, streamid=%s err=%v", err, streamid) 362 } else { 363 if time.Since(segstore.lastUpdated) > segRotateDuration*2 && segstore.RecordCount == 0 { 364 log.Infof("Deleting the segstore for streamid=%s", streamid) 365 delete(allSegStores, streamid) 366 } else { 367 log.Infof("Rotating segment due to time. streamid=%s and table=%s", streamid, segstore.VirtualTableName) 368 } 369 } 370 segstore.lock.Unlock() 371 }(sid, ss) 372 } 373 wg.Wait() 374 allSegStoresLock.RUnlock() 375 } 376 377 func ForceRotateSegmentsForTest() { 378 allSegStoresLock.Lock() 379 for streamid, segstore := range allSegStores { 380 segstore.lock.Lock() 381 err := segstore.AppendWipToSegfile(streamid, false, false, true) 382 if err != nil { 383 log.Errorf("ForceRotateSegmentsForTest: failed to append, streamid=%s err=%v", err, streamid) 384 } else { 385 log.Infof("Rotating segment due to time. streamid=%s and table=%s", streamid, segstore.VirtualTableName) 386 } 387 segstore.lock.Unlock() 388 } 389 allSegStoresLock.Unlock() 390 } 391 392 func timeBasedRotateSegment() { 393 for { 394 time.Sleep(SEGMENT_ROTATE_SLEEP_DURATION_SECONDS * time.Second) 395 rotateSegmentOnTime() 396 } 397 398 } 399 400 func FlushWipBufferToFile(sleepDuration *time.Duration) { 401 allSegStoresLock.RLock() 402 for streamid, segstore := range allSegStores { 403 segstore.lock.Lock() 404 if segstore.wipBlock.maxIdx > 0 && time.Since(segstore.lastUpdated) > *sleepDuration { 405 err := segstore.AppendWipToSegfile(streamid, false, false, false) 406 if err != nil { 407 log.Errorf("FlushWipBufferToFile: failed to append, err=%v", err) 408 } 409 log.Infof("Flushed WIP buffer due to time. streamid=%s and table=%s", streamid, segstore.VirtualTableName) 410 } 411 segstore.lock.Unlock() 412 } 413 allSegStoresLock.RUnlock() 414 } 415 416 func InitColWip(segKey string, colName string) *ColWip { 417 418 return &ColWip{ 419 csgFname: fmt.Sprintf("%v_%v.csg", segKey, xxhash.Sum64String(colName)), 420 deMap: make(map[string][]uint16), 421 deCount: 0, 422 } 423 } 424 425 // In-mem Buf Format 426 // [varint Record-0 varint Record-1 ....] 427 // varint stores length of Record , it would occupy 1-9 bytes 428 // The first bit of each byte of varint specifies whether there are follow on bytes 429 // rest 7 bits are used to store the number 430 func getSegStore(streamid string, ts_millis uint64, table string, orgId uint64) (*SegStore, error) { 431 432 allSegStoresLock.Lock() 433 defer allSegStoresLock.Unlock() 434 435 var segstore *SegStore 436 segstore, present := allSegStores[streamid] 437 if !present { 438 if len(allSegStores) >= maxAllowedSegStores { 439 return nil, fmt.Errorf("getSegStore: max allowed segstores reached (%d)", maxAllowedSegStores) 440 } 441 442 suffIndex, err := suffix.GetSuffix(streamid, table) 443 if err != nil { 444 return nil, err 445 } 446 segstore = &SegStore{suffix: suffIndex, lock: sync.Mutex{}, OrgId: orgId, firstTime: true} 447 segstore.initWipBlock() 448 err = segstore.resetSegStore(streamid, table) 449 if err != nil { 450 return nil, err 451 } 452 allSegStores[streamid] = segstore 453 instrumentation.SetWriterSegstoreCountGauge(int64(len(allSegStores))) 454 } 455 456 updateValuesFromConfig() 457 return segstore, nil 458 } 459 460 func getBlockBloomSize(bi *BloomIndex) uint32 { 461 462 if len(bi.HistoricalCount) == 0 { 463 bi.HistoricalCount = make([]uint32, 0) 464 return BLOCK_BLOOM_SIZE 465 } 466 467 startIdx := len(bi.HistoricalCount) - BLOOM_SIZE_HISTORY 468 if startIdx < 0 { 469 startIdx = 0 470 } 471 472 runningSum := uint32(0) 473 count := uint32(0) 474 for _, val := range bi.HistoricalCount[startIdx:] { 475 runningSum += val 476 count += 1 477 } 478 if count <= 0 { 479 return BLOCK_BLOOM_SIZE 480 } 481 482 nextBloomSize := runningSum / count 483 if nextBloomSize <= 0 { 484 return 1 485 } 486 return nextBloomSize 487 } 488 489 func getActiveBaseSegDir(streamid string, virtualTableName string, suffix uint64) string { 490 var sb strings.Builder 491 sb.WriteString(config.GetDataPath()) 492 sb.WriteString(config.GetHostID()) 493 sb.WriteString("/active/") 494 sb.WriteString(virtualTableName + "/") 495 sb.WriteString(streamid + "/") 496 sb.WriteString(strconv.FormatUint(suffix, 10) + "/") 497 basedir := sb.String() 498 return basedir 499 } 500 501 func getFinalBaseSegDir(streamid string, virtualTableName string, suffix uint64) string { 502 var sb strings.Builder 503 sb.WriteString(config.GetDataPath()) 504 sb.WriteString(config.GetHostID()) 505 sb.WriteString("/final/") 506 sb.WriteString(virtualTableName + "/") 507 sb.WriteString(streamid + "/") 508 sb.WriteString(strconv.FormatUint(suffix, 10) + "/") 509 basedir := sb.String() 510 return basedir 511 } 512 513 /* 514 Adds the fullWord and sub-words to the bloom 515 Subwords are gotten by splitting the fullWord by whitespace 516 */ 517 func addToBlockBloom(blockBloom *bloom.BloomFilter, fullWord []byte) uint32 { 518 519 var blockWordCount uint32 = 0 520 copy := fullWord[:] 521 522 if !blockBloom.TestAndAdd(copy) { 523 blockWordCount += 1 524 } 525 526 var foundWord bool 527 for { 528 i := bytes.Index(copy, BYTE_SPACE) 529 if i == -1 { 530 break 531 } 532 foundWord = true 533 if !blockBloom.TestAndAdd(copy[:i]) { 534 blockWordCount += 1 535 } 536 copy = copy[i+BYTE_SPACE_LEN:] 537 } 538 539 // handle last word. If no word was found, then we have already added the full word 540 if foundWord && len(copy) > 0 { 541 if !blockBloom.TestAndAdd(copy) { 542 blockWordCount += 1 543 } 544 } 545 return blockWordCount 546 } 547 548 func updateRangeIndex(key string, rangeIndexPtr map[string]*structs.Numbers, numType SS_IntUintFloatTypes, intVal int64, 549 uintVal uint64, fltVal float64) { 550 switch numType { 551 case SS_INT8, SS_INT16, SS_INT32, SS_INT64: 552 addIntToRangeIndex(key, intVal, rangeIndexPtr) 553 case SS_UINT8, SS_UINT16, SS_UINT32, SS_UINT64: 554 addUintToRangeIndex(key, uintVal, rangeIndexPtr) 555 case SS_FLOAT64: 556 addFloatToRangeIndex(key, fltVal, rangeIndexPtr) 557 } 558 } 559 560 func addUintToRangeIndex(key string, incomingVal uint64, rangeIndexPtr map[string]*structs.Numbers) { 561 existingRI, present := rangeIndexPtr[key] 562 if present { 563 inMemType := existingRI.NumType 564 switch inMemType { 565 case RNT_SIGNED_INT: 566 newVal := int64(incomingVal) 567 if newVal < existingRI.Min_int64 { 568 existingRI.Min_int64 = newVal 569 } else if newVal > existingRI.Max_int64 { 570 existingRI.Max_int64 = newVal 571 } 572 case RNT_FLOAT64: 573 newVal := float64(incomingVal) 574 if newVal < existingRI.Min_float64 { 575 existingRI.Min_float64 = newVal 576 } else if newVal > existingRI.Max_float64 { 577 existingRI.Max_float64 = newVal 578 } 579 default: 580 if incomingVal < existingRI.Min_uint64 { 581 existingRI.Min_uint64 = incomingVal 582 } else if incomingVal > existingRI.Max_uint64 { 583 existingRI.Max_uint64 = incomingVal 584 } 585 } 586 rangeIndexPtr[key] = existingRI 587 } else { 588 rangeIndexPtr[key] = &structs.Numbers{Min_uint64: incomingVal, Max_uint64: incomingVal, NumType: RNT_UNSIGNED_INT} 589 } 590 } 591 func addIntToRangeIndex(key string, incomingVal int64, rangeIndexPtr map[string]*structs.Numbers) { 592 existingRI, present := rangeIndexPtr[key] 593 if present { 594 inMemType := existingRI.NumType 595 switch inMemType { 596 case RNT_UNSIGNED_INT: 597 existingRI = &structs.Numbers{Min_int64: int64(rangeIndexPtr[key].Min_uint64), Max_int64: int64(rangeIndexPtr[key].Max_uint64), 598 NumType: RNT_SIGNED_INT} 599 if incomingVal < existingRI.Min_int64 { 600 existingRI.Min_int64 = incomingVal 601 } else if incomingVal > existingRI.Max_int64 { 602 existingRI.Max_int64 = incomingVal 603 } 604 case RNT_FLOAT64: 605 newVal := float64(incomingVal) 606 if newVal < existingRI.Min_float64 { 607 existingRI.Min_float64 = newVal 608 } else if newVal > existingRI.Max_float64 { 609 existingRI.Max_float64 = newVal 610 } 611 default: 612 if incomingVal < existingRI.Min_int64 { 613 existingRI.Min_int64 = incomingVal 614 } else if incomingVal > existingRI.Max_int64 { 615 existingRI.Max_int64 = incomingVal 616 } 617 } 618 rangeIndexPtr[key] = existingRI 619 //fmt.Printf("present %v\n", (*rangeIndexPtr)) 620 } else { 621 rangeIndexPtr[key] = &structs.Numbers{Min_int64: incomingVal, Max_int64: incomingVal, NumType: RNT_SIGNED_INT} 622 //fmt.Printf("ADDED %v\n", (*rangeIndexPtr)) 623 } 624 } 625 func addFloatToRangeIndex(key string, incomingVal float64, rangeIndexPtr map[string]*structs.Numbers) { 626 existingRI, present := rangeIndexPtr[key] 627 if present { 628 inMemType := existingRI.NumType 629 switch inMemType { 630 case RNT_UNSIGNED_INT: 631 existingRI = &structs.Numbers{Min_float64: float64(rangeIndexPtr[key].Min_uint64), Max_float64: float64(rangeIndexPtr[key].Max_uint64), NumType: RNT_FLOAT64} 632 case RNT_SIGNED_INT: 633 existingRI = &structs.Numbers{Min_float64: float64(rangeIndexPtr[key].Min_int64), Max_float64: float64(rangeIndexPtr[key].Max_int64), NumType: RNT_FLOAT64} 634 } 635 if incomingVal < existingRI.Min_float64 { 636 existingRI.Min_float64 = incomingVal 637 } else if incomingVal > existingRI.Max_float64 { 638 existingRI.Max_float64 = incomingVal 639 } 640 rangeIndexPtr[key] = existingRI 641 } else { 642 rangeIndexPtr[key] = &structs.Numbers{Min_float64: incomingVal, Max_float64: incomingVal, NumType: RNT_FLOAT64} 643 } 644 } 645 646 /* 647 ******************* WIP BLOCK Encoding ******************** 648 649 [Actual Block] 650 // lens are stored in the bsu file 651 652 */ 653 // returns number of written bytes, offset of block in file, and any errors 654 655 func writeWip(colWip *ColWip, encType []byte) (uint32, int64, error) { 656 657 blkLen := uint32(0) 658 // todo better error handling should not exit 659 fd, err := os.OpenFile(colWip.csgFname, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644) 660 if err != nil { 661 log.Errorf("WriteWip: open failed fname=%v, err=%v", colWip.csgFname, err) 662 return 0, 0, err 663 } 664 defer fd.Close() 665 666 blkOffset, err := fd.Seek(0, 2) // go to the end of the file 667 if err != nil { 668 log.Errorf("WriteWip: failed to get offset of current block offset %+v", err) 669 return 0, 0, err 670 } 671 672 _, err = fd.Write(encType) 673 if err != nil { 674 log.Errorf("WriteWip: compression Type write failed fname=%v, err=%v", colWip.csgFname, err) 675 return 0, blkOffset, err 676 } 677 blkLen += 1 // for compression type 678 679 compressed, compLen, err := compressWip(colWip, encType) 680 if err != nil { 681 log.Errorf("WriteWip: compression of wip failed fname=%v, err=%v", colWip.csgFname, err) 682 return 0, blkOffset, err 683 } 684 _, err = fd.Write(compressed) 685 if err != nil { 686 log.Errorf("WriteWip: compressed write failed fname=%v, err=%v", colWip.csgFname, err) 687 return 0, blkOffset, err 688 } 689 blkLen += compLen 690 691 return blkLen, blkOffset, nil 692 } 693 694 func compressWip(colWip *ColWip, encType []byte) ([]byte, uint32, error) { 695 var compressed []byte 696 if bytes.Equal(encType, ZSTD_COMLUNAR_BLOCK) { 697 compressed = encoder.EncodeAll(colWip.cbuf[0:colWip.cbufidx], make([]byte, 0, colWip.cbufidx)) 698 } else if bytes.Equal(encType, TIMESTAMP_TOPDIFF_VARENC) { 699 compressed = colWip.cbuf[0:colWip.cbufidx] 700 } else if bytes.Equal(encType, ZSTD_DICTIONARY_BLOCK) { 701 PackDictEnc(colWip) 702 compressed = colWip.cbuf[0:colWip.cbufidx] 703 } else { 704 log.Errorf("compressWip got an unknown encoding type: %+v", encType) 705 return nil, 0, fmt.Errorf("got an unknown encoding type: %+v", encType) 706 } 707 compLen := uint32(len(compressed)) 708 709 return compressed, compLen, nil 710 } 711 712 func writeRunningSegMeta(fname string, rsm *structs.SegMeta) error { 713 714 fd, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) 715 if err != nil { 716 log.Errorf("writeRunningSegMeta: open failed fname=%v, err=%v", fname, err) 717 return err 718 } 719 defer fd.Close() 720 721 rsmjson, err := json.Marshal(rsm) 722 if err != nil { 723 log.Errorf("writeRunningSegMeta: failed to Marshal: err=%v", err) 724 return err 725 } 726 727 if _, err := fd.Write(rsmjson); err != nil { 728 log.Errorf("writeRunningSegMeta: failed to write rsmjson filename=%v: err=%v", fname, err) 729 return err 730 } 731 732 return nil 733 } 734 735 func GetUnrotatedVTableCounts(vtable string, orgid uint64) (uint64, int, uint64) { 736 bytesCount := uint64(0) 737 onDiskBytesCount := uint64(0) 738 recCount := 0 739 allSegStoresLock.RLock() 740 defer allSegStoresLock.RUnlock() 741 for _, segstore := range allSegStores { 742 if segstore.VirtualTableName == vtable && segstore.OrgId == orgid { 743 bytesCount += segstore.BytesReceivedCount 744 recCount += segstore.RecordCount 745 onDiskBytesCount += segstore.OnDiskBytes 746 } 747 } 748 return bytesCount, recCount, onDiskBytesCount 749 } 750 751 func getActiveBaseDirVTable(virtualTableName string) string { 752 var sb strings.Builder 753 sb.WriteString(config.GetRunningConfig().DataPath) 754 sb.WriteString(config.GetHostID()) 755 sb.WriteString("/active/") 756 sb.WriteString(virtualTableName + "/") 757 basedir := sb.String() 758 return basedir 759 } 760 761 func DeleteVirtualTableSegStore(virtualTableName string) { 762 allSegStoresLock.Lock() 763 for streamid, segstore := range allSegStores { 764 if segstore.VirtualTableName == virtualTableName { 765 delete(allSegStores, streamid) 766 } 767 } 768 activedir := getActiveBaseDirVTable(virtualTableName) 769 os.RemoveAll(activedir) 770 allSegStoresLock.Unlock() 771 } 772 773 func DeleteSegmentsForIndex(segmetaFName, indexName string) { 774 smrLock.Lock() 775 defer smrLock.Unlock() 776 777 removeSegmentsByIndexOrList(segmetaFName, indexName, nil) 778 } 779 780 func RemoveSegments(segmetaFName string, segmentsToDelete map[string]*structs.SegMeta) { 781 smrLock.Lock() 782 defer smrLock.Unlock() 783 784 removeSegmentsByIndexOrList(segmetaFName, "", segmentsToDelete) 785 } 786 787 func removeSegmentsByIndexOrList(segMetaFile string, indexName string, segmentsToDelete map[string]*structs.SegMeta) { 788 789 if indexName == "" && segmentsToDelete == nil { 790 return // nothing to remove 791 } 792 793 preservedSmEntries := make([]*structs.SegMeta, 0) 794 795 entriesRead := 0 796 entriesRemoved := 0 797 798 fr, err := os.OpenFile(segMetaFile, os.O_RDONLY, 0644) 799 if err != nil { 800 log.Errorf("removeSegmentsByIndexOrList: Failed to open SegMetaFile name=%v, err:%v", segMetaFile, err) 801 return 802 } 803 defer fr.Close() 804 805 reader := bufio.NewScanner(fr) 806 for reader.Scan() { 807 segMetaData := structs.SegMeta{} 808 err = json.Unmarshal(reader.Bytes(), &segMetaData) 809 if err != nil { 810 log.Errorf("removeSegmentsByIndexOrList: Failed to unmarshal fileName=%v, err:%v", segMetaFile, err) 811 continue 812 } 813 entriesRead++ 814 815 // only append the ones that we want to preserve 816 // check if it was based on indexName 817 if indexName != "" { 818 if segMetaData.VirtualTableName != indexName { 819 preservedSmEntries = append(preservedSmEntries, &segMetaData) 820 continue 821 } 822 } else { 823 // check if based on segmetas 824 _, ok := segmentsToDelete[segMetaData.SegmentKey] 825 if !ok { 826 preservedSmEntries = append(preservedSmEntries, &segMetaData) 827 continue 828 } 829 } 830 831 entriesRemoved++ 832 if err := os.RemoveAll(segMetaData.SegbaseDir); err != nil { 833 log.Errorf("removeSegmentsByIndexOrList: Failed to remove directory name=%v, err:%v", 834 segMetaData.SegbaseDir, err) 835 } 836 fileutils.RecursivelyDeleteEmptyParentDirectories(segMetaData.SegbaseDir) 837 } 838 839 if entriesRemoved > 0 { 840 841 // if we removed entries and there was nothing preserveed then we must delete this segmetafile 842 if len(preservedSmEntries) == 0 { 843 if err := os.RemoveAll(segMetaFile); err != nil { 844 log.Errorf("removeSegmentsByIndexOrList: Failed to remove smfile name=%v, err:%v", segMetaFile, err) 845 } 846 return 847 } 848 849 wfd, err := os.OpenFile(segMetaFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) 850 if err != nil { 851 log.Errorf("removeSegmentsByIndexOrList: Failed to open temp SegMetaFile name=%v, err:%v", segMetaFile, err) 852 return 853 } 854 defer wfd.Close() 855 856 for _, smentry := range preservedSmEntries { 857 858 segmetajson, err := json.Marshal(*smentry) 859 if err != nil { 860 log.Errorf("removeSegmentsByIndexOrList: failed to Marshal: err=%v", err) 861 return 862 } 863 864 if _, err := wfd.Write(segmetajson); err != nil { 865 log.Errorf("removeSegmentsByIndexOrList: failed to write segmeta filename=%v: err=%v", segMetaFile, err) 866 return 867 } 868 869 if _, err := wfd.WriteString("\n"); err != nil { 870 log.Errorf("removeSegmentsByIndexOrList: failed to write newline filename=%v: err=%v", segMetaFile, err) 871 return 872 } 873 } 874 } 875 } 876 877 func DeleteOldKibanaDoc(indexNameConverted string, idVal string) { 878 indexNameDirPath := KibanaInternalBaseDir + indexNameConverted 879 hashDocId := utils.HashString(idVal) 880 docFilePath := indexNameDirPath + "/" + hashDocId 881 882 err := os.RemoveAll(docFilePath) 883 if err != nil { 884 log.Errorf("DeleteOldKibanaDoc: Failed to delete, indexNameDirPath %+v idVal %+v folderpath %+v, err %+v", 885 indexNameDirPath, idVal, docFilePath, err) 886 } 887 } 888 889 func (cw *ColWip) GetBufAndIdx() ([]byte, uint32) { 890 return cw.cbuf[0:cw.cbufidx], cw.cbufidx 891 } 892 893 func (cw *ColWip) SetDeCount(val uint16) { 894 cw.deCount = val 895 } 896 897 func (cw *ColWip) SetDeMap(val map[string][]uint16) { 898 cw.deMap = val 899 } 900 901 func (cw *ColWip) WriteSingleString(value string) { 902 copy(cw.cbuf[cw.cbufidx:], VALTYPE_ENC_SMALL_STRING[:]) 903 cw.cbufidx += 1 904 n := uint16(len(value)) 905 copy(cw.cbuf[cw.cbufidx:], utils.Uint16ToBytesLittleEndian(n)) 906 cw.cbufidx += 2 907 copy(cw.cbuf[cw.cbufidx:], value) 908 cw.cbufidx += uint32(n) 909 } 910 911 func AddNewRotatedSegment(segmeta structs.SegMeta) { 912 913 smrLock.Lock() 914 defer smrLock.Unlock() 915 916 fileName := GetLocalSegmetaFName() 917 918 segmetajson, err := json.Marshal(segmeta) 919 if err != nil { 920 log.Errorf("AddNewRotatedSegment: failed to Marshal: err=%v", err) 921 return 922 } 923 924 fd, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644) 925 if err != nil { 926 if errors.Is(err, os.ErrNotExist) { 927 fd, err = os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) 928 if err != nil { 929 log.Errorf("AddNewRotatedSegment: failed to open a new filename=%v: err=%v", fileName, err) 930 return 931 } 932 933 } else { 934 log.Errorf("AddNewRotatedSegment: failed to open filename=%v: err=%v", fileName, err) 935 return 936 } 937 } 938 939 defer fd.Close() 940 941 if _, err := fd.Write(segmetajson); err != nil { 942 log.Errorf("AddNewRotatedSegment: failed to write segmeta filename=%v: err=%v", fileName, err) 943 return 944 } 945 946 if _, err := fd.WriteString("\n"); err != nil { 947 log.Errorf("AddNewRotatedSegment: failed to write newline filename=%v: err=%v", fileName, err) 948 return 949 } 950 err = fd.Sync() 951 if err != nil { 952 log.Errorf("AddNewRotatedSegment: failed to sync filename=%v: err=%v", fileName, err) 953 return 954 } 955 } 956 957 func BackFillPQSSegmetaEntry(segsetkey string, newpqid string) { 958 smrLock.Lock() 959 defer smrLock.Unlock() 960 961 preservedSmEntries := make([]*structs.SegMeta, 0) 962 allPqids := make(map[string]bool) 963 964 // Read segmeta files 965 allSegMetas, err := getAllSegmetaToMap(localSegmetaFname) 966 if err != nil { 967 log.Errorf("BackFillPQSSegmetaEntry: failed to get Segmeta: err=%v", err) 968 return 969 } 970 for segkey, segMetaEntry := range allSegMetas { 971 if segkey != segsetkey { 972 preservedSmEntries = append(preservedSmEntries, segMetaEntry) 973 continue 974 } else { 975 for pqid := range segMetaEntry.AllPQIDs { 976 allPqids[pqid] = true 977 } 978 allPqids[newpqid] = true 979 segMetaEntry.AllPQIDs = allPqids 980 preservedSmEntries = append(preservedSmEntries, segMetaEntry) 981 continue 982 } 983 } 984 wfd, err := os.OpenFile(localSegmetaFname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) 985 if err != nil { 986 log.Errorf("BackFillPQSSegmetaEntry: Failed to open SegMetaFile name=%v, err:%v", localSegmetaFname, err) 987 return 988 } 989 defer wfd.Close() 990 991 for _, smentry := range preservedSmEntries { 992 993 segmetajson, err := json.Marshal(*smentry) 994 if err != nil { 995 log.Errorf("BackFillPQSSegmetaEntry: failed to Marshal: err=%v", err) 996 return 997 } 998 999 if _, err := wfd.Write(segmetajson); err != nil { 1000 log.Errorf("BackFillPQSSegmetaEntry: failed to write segmeta filename=%v: err=%v", localSegmetaFname, err) 1001 return 1002 } 1003 1004 if _, err := wfd.WriteString("\n"); err != nil { 1005 log.Errorf("BackFillPQSSegmetaEntry: failed to write newline filename=%v: err=%v", localSegmetaFname, err) 1006 return 1007 } 1008 } 1009 }