| 879 | }; |
| 880 | |
| 881 | class DiskQueue final : public IDiskQueue, public Tracked<DiskQueue> { |
| 882 | public: |
| 883 | // FIXME: Is setting lastCommittedSeq to -1 instead of 0 necessary? |
| 884 | DiskQueue(std::string basename, |
| 885 | std::string fileExtension, |
| 886 | UID dbgid, |
| 887 | DiskQueueVersion diskQueueVersion, |
| 888 | int64_t fileSizeWarningLimit) |
| 889 | : rawQueue(new RawDiskQueue_TwoFiles(basename, fileExtension, dbgid, fileSizeWarningLimit)), dbgid(dbgid), |
| 890 | diskQueueVersion(diskQueueVersion), anyPopped(false), warnAlwaysForMemory(true), nextPageSeq(0), poppedSeq(0), |
| 891 | lastPoppedSeq(0), lastCommittedSeq(-1), pushed_page_buffer(nullptr), recovered(false), initialized(false), |
| 892 | nextReadLocation(-1), readBufPage(nullptr), readBufPos(0) {} |
| 893 | |
| 894 | location push(StringRef contents) override { |
| 895 | ASSERT(recovered); |
| 896 | uint8_t const* begin = contents.begin(); |
| 897 | uint8_t const* end = contents.end(); |
| 898 | CODE_PROBE(contents.size() && pushedPageCount(), "More than one push between commits"); |
| 899 | |
| 900 | bool pushAtEndOfPage = contents.size() >= 4 && pushedPageCount() && backPage().remainingCapacity() < 4; |
| 901 | CODE_PROBE(pushAtEndOfPage, "Push right at the end of a page, possibly splitting size"); |
| 902 | while (begin != end) { |
| 903 | if (!pushedPageCount() || !backPage().remainingCapacity()) |
| 904 | addEmptyPage(); |
| 905 | |
| 906 | auto& p = backPage(); |
| 907 | int s = std::min<int>(p.remainingCapacity(), end - begin); |
| 908 | memcpy(p.payload + p.payloadSize, begin, s); |
| 909 | p.payloadSize += s; |
| 910 | begin += s; |
| 911 | } |
| 912 | return endLocation(); |
| 913 | } |
| 914 | |
| 915 | void pop(location upTo) override { |
| 916 | ASSERT(!upTo.hi); |
| 917 | ASSERT(!recovered || upTo.lo <= endLocation()); |
| 918 | |
| 919 | // SS can pop pages that have not been sync.ed to disk because of concurrency: |
| 920 | // SS can read (i.e., pop) data at the same time or before tLog syncs the page to disk. |
| 921 | // This is rare in real situation but common in simulation. |
| 922 | // The following ASSERT is NOT part of the intended contract of IDiskQueue, but alerts the user to a known bug |
| 923 | // where popping |
| 924 | // into uncommitted pages can cause a durability failure. |
| 925 | // FIXME: Remove this ASSERT when popping into uncommitted pages is fixed |
| 926 | if (upTo.lo > lastCommittedSeq) { |
| 927 | TraceEvent(SevError, "DQPopUncommittedData", dbgid) |
| 928 | .detail("UpTo", upTo) |
| 929 | .detail("LastCommittedSeq", lastCommittedSeq) |
| 930 | .detail("File0Name", rawQueue->files[0].dbgFilename); |
| 931 | } |
| 932 | if (upTo.lo > poppedSeq) { |
| 933 | poppedSeq = upTo.lo; |
| 934 | anyPopped = true; |
| 935 | } |
| 936 | } |
| 937 | |
| 938 | Future<Standalone<StringRef>> read(location from, location to, CheckHashes ch) override { |
nothing calls this directly
no test coverage detected