* Reads the metadata necessary to decompress log messsages from a log file. * This function can be invoked incrementally to build a larger dictionary from * smaller fragments in the file and it should only be invoked once per fragment * * \param fd * File descriptor pointing to the dictionary fragment * \param flushOldDictionary * Removes the old dictionary entries * \return *
| 634 | * true if successful, false if the dictionary was corrupt |
| 635 | */ |
| 636 | bool |
| 637 | Log::Decoder::readDictionary(FILE *fd, bool flushOldDictionary) { |
| 638 | if (!readCheckpoint(checkpoint, fd)) { |
| 639 | fprintf(stderr, "Error: Could not read initial checkpoint, " |
| 640 | "the compressed log may be corrupted.\r\n"); |
| 641 | return false; |
| 642 | } |
| 643 | |
| 644 | size_t bytesRead = fread(endOfRawMetadata, 1, checkpoint.newMetadataBytes, |
| 645 | fd); |
| 646 | if (bytesRead != checkpoint.newMetadataBytes) { |
| 647 | fprintf(stderr, "Error couldn't read metadata header in log file.\r\n"); |
| 648 | return false; |
| 649 | } |
| 650 | |
| 651 | if (flushOldDictionary) { |
| 652 | endOfRawMetadata = rawMetadata; |
| 653 | fmtId2metadata.clear(); |
| 654 | fmtId2fmtString.clear(); |
| 655 | } |
| 656 | |
| 657 | // Build an index of format id to metadata |
| 658 | const char *start = endOfRawMetadata; |
| 659 | const char *newEnd = endOfRawMetadata + bytesRead; |
| 660 | while(endOfRawMetadata < newEnd) { |
| 661 | std::string fmtString; |
| 662 | fmtId2metadata.push_back(endOfRawMetadata); |
| 663 | |
| 664 | // Skip ahead |
| 665 | auto *fm = reinterpret_cast<FormatMetadata*>(endOfRawMetadata); |
| 666 | endOfRawMetadata += sizeof(FormatMetadata) + fm->filenameLength; |
| 667 | |
| 668 | for (int i = 0; i < fm->numPrintFragments |
| 669 | && newEnd >= endOfRawMetadata; ++i) |
| 670 | { |
| 671 | auto *pf = reinterpret_cast<PrintFragment*>(endOfRawMetadata); |
| 672 | endOfRawMetadata += sizeof(PrintFragment) + pf->fragmentLength; |
| 673 | fmtString.append(pf->formatFragment); |
| 674 | } |
| 675 | |
| 676 | fmtId2fmtString.push_back(fmtString); |
| 677 | } |
| 678 | |
| 679 | if (newEnd != endOfRawMetadata) { |
| 680 | fprintf(stderr, "Error: Log dictionary is inconsistent; " |
| 681 | "expected %lu bytes, but read %lu bytes\r\n", |
| 682 | newEnd - start, |
| 683 | endOfRawMetadata - start); |
| 684 | return false; |
| 685 | } |
| 686 | |
| 687 | if (fmtId2metadata.size() != checkpoint.totalMetadataEntries) { |
| 688 | fprintf(stderr, "Error: Missing log metadata detected; " |
| 689 | "expected %u messages, but only found %lu\r\n", |
| 690 | checkpoint.totalMetadataEntries, |
| 691 | fmtId2metadata.size()); |
| 692 | return false; |
| 693 | } |