Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions source/dcautil/dca.c
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,9 @@ static FileDescriptor* getFileDeltaInMemMapAndSearch(const int fd, const off_t s
off_t offset_in_page_size_multiple ;
unsigned int bytes_ignored = 0, bytes_ignored_main = 0, bytes_ignored_rotated = 0;
off_t main_fsize = 0, rotated_fsize = 0;
// Log upload backs up and truncates in place, so the stored seek no longer refers
// to any data still present in this file.
const bool truncated = (seek_value > sb.st_size);
// Find the nearest multiple of page size
if (seek_value > 0 && PAGESIZE > 0)
{
Expand Down Expand Up @@ -1186,9 +1189,19 @@ static FileDescriptor* getFileDeltaInMemMapAndSearch(const int fd, const off_t s
// No inode change (seek_value > sb.st_size or check_rotated path)
// Legacy behavior: read entire rotated + current from seek
rotated_fsize = rb.st_size;
main_fsize = sb.st_size - seek_value;
bytes_ignored_main = bytes_ignored;
addrcf = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, tmp_fd, offset_in_page_size_multiple);
if(truncated)
{
// Stale seek points past the truncated file - read all of it
main_fsize = sb.st_size;
bytes_ignored_main = 0;
addrcf = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, tmp_fd, 0);
}
else
{
main_fsize = sb.st_size - seek_value;
bytes_ignored_main = bytes_ignored;
addrcf = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, tmp_fd, offset_in_page_size_multiple);
}
addrrf = mmap(NULL, rb.st_size, PROT_READ, MAP_PRIVATE, tmp_rd, 0);
}
if(tmp_rd != -1)
Expand Down Expand Up @@ -1216,6 +1229,16 @@ static FileDescriptor* getFileDeltaInMemMapAndSearch(const int fd, const off_t s
bytes_ignored_main = bytes_ignored;
main_fsize = sb.st_size - seek_value;
}
else if(truncated)
{
// Truncated in place with no rotated file to fall back on - read the
// entire current file so its markers are still collected this cycle
T2Info("Log file %s truncated (seek %jd > size %jd), reading entire current file\n",
logFile, (intmax_t)seek_value, (intmax_t)sb.st_size);
addrcf = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, tmp_fd, 0);
bytes_ignored_main = 0;
main_fsize = sb.st_size;
}
else
{

Expand Down
85 changes: 85 additions & 0 deletions source/test/dcautils/dcautilTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1771,6 +1771,91 @@ TEST_F(dcaTestFixture, getDCAResultsInVector_MultiRotation_IntermediateFile)
Vector_Destroy(vecMarkerList, freeGMarker);
}

// TCXB7-7251: PARODUSlog.txt truncated in place by log upload with no rotated
// backup available - stale seek must not cause the marker to be dropped.
TEST_F(dcaTestFixture, getDCAResultsInVector_TruncatedInPlace_NoRotatedFile)
{
GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile));
gsProfile->logFileSeekMap = hash_map_create();
gsProfile->execCounter = 2;
long *tempnum;
double val = 5000;
tempnum = (long *)malloc(sizeof(long));
*tempnum = (long)val;
hash_map_put(gsProfile->logFileSeekMap, strdup("PARODUSlog.txt"), (void*)tempnum, free);

Vector* vecMarkerList = NULL;
Vector_Create(&vecMarkerList);
GrepMarker* marker = (GrepMarker*) malloc(sizeof(GrepMarker));
memset(marker, 0, sizeof(GrepMarker));
marker->markerName = strdup("SYS_INFO_LowQosEvntUpload");
marker->searchString = strdup("PARODUS: Low qos event");
marker->trimParam = true;
marker->regexParam = strdup("[0-9]+");
marker->logFile = strdup("PARODUSlog.txt");
marker->skipFreq = 0;
marker->paramType = strdup("grep");
marker->mType = MTYPE_COUNTER;
marker->u.count = 0;
marker->reportEmptyParam = true;
Vector_PushBack(vecMarkerList, (void*) marker);

//freeFileDescriptor
EXPECT_CALL(*g_fileIOMock, munmap(_, _))
.Times(1)
.WillOnce(Return(0));
EXPECT_CALL(*g_fileIOMock, close(_))
.Times(2)
.WillOnce(Return(0))
.WillOnce(Return(0));

//getLogFileDescriptor opens the current (truncated) file, then
//getRotatedLogFileDescriptor fails to open the missing .1 file
EXPECT_CALL(*g_fileIOMock, open(_,_))
.Times(2)
.WillOnce(Return(0))
.WillOnce(Return(-1));
EXPECT_CALL(*g_fileIOMock, fstat(_, _))
.Times(2)
.WillOnce([](int fd, struct stat* statbuf) {
statbuf->st_size = 800; // Truncated file size, smaller than stored seek 5000
return 0;
})
.WillOnce([](int fd, struct stat* statbuf) {
statbuf->st_size = 800;
return 0;
});

//getDeltainmmapsearch - only the current file is staged, no rotated tmp file
EXPECT_CALL(*g_fileIOMock, mkstemp(_))
.Times(1)
.WillOnce(Return(0));
EXPECT_CALL(*g_systemMock, unlink(_))
.Times(1)
.WillOnce(Return(0));
EXPECT_CALL(*g_fileIOMock,sendfile(_,_,_,_))
.Times(1)
.WillOnce(Return(800));
EXPECT_CALL(*g_fileIOMock, mmap(_,_,_,_,_,_))
.Times(1)
.WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
EXPECT_EQ(0, offset); // Entire current file read from offset 0 despite stale seek
const char* test_str = "PARODUS: Low qos event, send success callback and delete\n";
char* mapped_mem = (char*)malloc(length);
memset(mapped_mem, 0, length);
strncpy(mapped_mem, test_str, length - 1);
return (void*)mapped_mem;
});

EXPECT_EQ(0, getDCAResultsInVector(gsProfile, vecMarkerList, false, "/opt/logs"));
EXPECT_EQ(1, marker->u.count); // Marker must still be captured despite the truncation

hash_map_destroy(gsProfile->logFileSeekMap, free);
gsProfile->logFileSeekMap = NULL;
free(gsProfile);
Vector_Destroy(vecMarkerList, freeGMarker);
}

TEST_F(dcaTestFixture, T2InitProperties)
{
EXPECT_CALL(*g_fileIOMock, fopen(_,_))
Expand Down
Loading