foundationdb/fdbrpc/TraceFileIO.cpp

166 lines
7.1 KiB
C++

/*
* TraceFileIO.cpp
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fdbrpc/TraceFileIO.h"
#if CENABLED(0, NOT_IN_CLEAN)
//TO RUN: Set the name of file you wish to track
std::string debugFileName = "storage-3807bf710afaa6d39d23db60d6e687c8.fdb-wal";
std::map<int64_t, uint8_t*> debugFileData;
std::map<int64_t, uint8_t*> debugFileMask;
std::map<int64_t, int64_t> debugFileRegions;
uint8_t *debugFileSetPage;
//Setup memory data structures for file debugging.
//TO RUN: setup debugFileRegions map with the regions of the file you wish to track. Keys of the map are offsets in the file,
//and values are the lengths of the region
void debugFileSetup() {
debugFileRegions[0] = 1e8;
for(auto itr = debugFileRegions.begin(); itr != debugFileRegions.end(); ++itr) {
debugFileData[itr->first] = (uint8_t*)malloc(itr->second);
memset(debugFileData[itr->first], 0, itr->second);
debugFileMask[itr->first] = (uint8_t*)malloc(itr->second);
memset(debugFileMask[itr->first], 0, itr->second);
}
debugFileSetPage = (uint8_t*)malloc(4096);
memset(debugFileSetPage, 1, 4096);
}
//Trim a file path to the file name
std::string debugFileTrim(std::string filename) {
int index = filename.find_last_of("/");
if(index == filename.npos)
return filename;
else
return filename.substr(index + 1);
}
//Checks if a block of memory has been written
bool debugFileIsSet(uint8_t *storeMask, int64_t offset, int64_t length) {
for(int64_t i = 0; i < length; i += 4096)
if(memcmp(&storeMask[offset + i], debugFileSetPage, std::min((int64_t)4096, length - i)))
return false;
return true;
}
//Checks that a given block of data is the same as what has been written by a call to debugFileSet
void debugFileCheck(std::string context, std::string file, const void *data, int64_t offset, int length) {
if(debugFileRegions.empty())
debugFileSetup();
if(debugFileTrim(file) == debugFileName) {
bool found = false;
for(auto itr = debugFileRegions.begin(); itr != debugFileRegions.end(); ++itr) {
if(offset + length > itr->first && offset < itr->first + itr->second) {
found = true;
uint8_t *storeData = debugFileData[itr->first];
uint8_t *storeMask = debugFileMask[itr->first];
ASSERT(storeData && storeMask);
int64_t dataOffset = std::max((int64_t)0, itr->first - offset);
int64_t dbgOffset = std::max((int64_t)0, offset - itr->first);
int64_t cmpLength = std::min(length - dataOffset, itr->second - dbgOffset);
ASSERT(cmpLength > 0);
TraceEvent("DebugFileCheck").detail("Context", context).detail("Filename", file).detail("Offset", offset).detail("Length", length);
bool success = true;
if(debugFileIsSet(storeMask, dbgOffset, cmpLength)) {
//TraceEvent("DebugFileCheckMemCmp").detail("Context", context).detail("Filename", file).detail("Offset", offset).detail("Length", length).detail("DataOffset", dataOffset).detail("DbgOffset", dbgOffset).detail("OverlapLength", cmpLength);
if(memcmp(&((uint8_t*)data)[dataOffset], &storeData[dbgOffset], cmpLength))
success = false;
}
else {
TraceEvent("DebugFileUnsetCheck").detail("Context", context).detail("Filename", file).detail("Offset", offset).detail("Length", length);
for(int64_t i = 0; i < cmpLength; i++) {
if(storeMask[dbgOffset + i] && storeData[dbgOffset + i] != ((uint8_t*)data)[dataOffset + i]) {
success = false;
break;
}
}
}
if(!success)
TraceEvent(SevWarnAlways, "DebugFileFail").detail("Context", context).detail("Filename", file).detail("Offset", offset).detail("Length", length);
}
}
if(!found)
TraceEvent("DebugFileSkippingCheck").detail("Context", context).detail("Filename", file).detail("Offset", offset).detail("Length", length);
}
}
//Updates the in-memory copy of tracked data at a given offset
void debugFileSet(std::string context, std::string file, const void *data, int64_t offset, int length) {
if(debugFileRegions.empty())
debugFileSetup();
if(debugFileTrim(file) == debugFileName) {
bool found = false;
for(auto itr = debugFileRegions.begin(); itr != debugFileRegions.end(); ++itr) {
if(offset + length > itr->first && offset < itr->first + itr->second) {
found = true;
uint8_t *storeData = debugFileData[itr->first];
uint8_t *storeMask = debugFileMask[itr->first];
ASSERT(storeData && storeMask);
int64_t dataOffset = std::max((int64_t)0, itr->first - offset);
int64_t dbgOffset = std::max((int64_t)0, offset - itr->first);
int64_t cmpLength = std::min(length - dataOffset, itr->second - dbgOffset);
ASSERT(cmpLength > 0);
TraceEvent("DebugFileSet").detail("Context", context).detail("Filename", file).detail("Offset", offset).detail("Length", length);
//TraceEvent("DebugFileSetMemCpy").detail("Context", context).detail("Filename", file).detail("Offset", offset).detail("Length", length).detail("DataOffset", dataOffset).detail("DbgOffset", dbgOffset).detail("OverlapLength", std::min(length - dataOffset, itr->second - dbgOffset));
memcpy(&storeData[dbgOffset], &((uint8_t*)data)[dataOffset], cmpLength);
memset(&storeMask[dbgOffset], 1, cmpLength);
}
}
if(!found)
TraceEvent("DebugFileSkippingSet").detail("Context", context).detail("Filename", file).detail("Offset", offset).detail("Length", length);
}
}
//Updates the in-memory copy of tracked data to account for truncates (this simply invalidates any data after truncate point)
void debugFileTruncate(std::string context, std::string file, int64_t offset) {
if(debugFileRegions.empty())
debugFileSetup();
if(debugFileTrim(file) == debugFileName) {
bool found = false;
for(auto itr = debugFileRegions.begin(); itr != debugFileRegions.end(); ++itr) {
if(itr->first + itr->second > offset) {
found = true;
TraceEvent("DebugFileTruncate").detail("Context", context).detail("Filename", file).detail("Offset", offset);
uint8_t *storeMask = debugFileMask[itr->first];
ASSERT(storeMask);
int64_t dbgOffset = std::max((int64_t)0, offset - itr->first);
memset(&storeMask[dbgOffset], 0, itr->second - dbgOffset);
}
}
if(!found)
TraceEvent("DebugFileSkippingTruncate").detail("Context", context).detail("Filename", file).detail("Offset", offset);
}
}
#else
void debugFileCheck(std::string context, std::string file, const void *data, int64_t offset, int length) { }
void debugFileSet(std::string context, std::string file, const void *data, int64_t offset, int length) { }
void debugFileTruncate(std::string context, std::string file, int64_t offset) { }
#endif