Status FTDCFileManager::rotate(Client* client) { auto s = _writer.close(); if (!s.isOK()) { return s; } auto files = scanDirectory(); // Rotate as needed trimDirectory(files); auto swFile = generateArchiveFileName(_path, terseUTCCurrentTime()); if (!swFile.isOK()) { return swFile.getStatus(); } return openArchiveFile(client, swFile.getValue(), {}); }
StatusWith<std::unique_ptr<FTDCFileManager>> FTDCFileManager::create( const FTDCConfig* config, const boost::filesystem::path& path, FTDCCollectorCollection* collection, Client* client) { const boost::filesystem::path dir = boost::filesystem::absolute(path); if (!boost::filesystem::exists(dir)) { // Create the directory boost::system::error_code ec; boost::filesystem::create_directories(dir, ec); if (ec) { return {ErrorCodes::NonExistentPath, str::stream() << "\'" << dir.generic_string() << "\' could not be created: " << ec.message()}; } } auto mgr = std::unique_ptr<FTDCFileManager>(new FTDCFileManager(config, dir, std::move(collection))); // Enumerate the metrics files auto files = mgr->scanDirectory(); // Recover the interim file auto interimDocs = mgr->recoverInterimFile(); // Open the archive file for writing auto swFile = mgr->generateArchiveFileName(path, terseUTCCurrentTime()); if (!swFile.isOK()) { return swFile.getStatus(); } Status s = mgr->openArchiveFile(client, swFile.getValue(), interimDocs); if (!s.isOK()) { return s; } // Rotate as needed after we appended interim data to the archive file mgr->trimDirectory(files); return {std::move(mgr)}; }
// Test a restart after a crash with a corrupt archive file TEST(FTDCFileManagerTest, TestCorruptCrashRestart) { Client* client = &cc(); FTDCConfig c; c.maxFileSizeBytes = 1000; c.maxDirectorySizeBytes = 3000; unittest::TempDir tempdir("metrics_testpath"); boost::filesystem::path dir(tempdir.path()); createDirectoryClean(dir); for (int i = 0; i < 2; i++) { // Do a few cases of stop and start to ensure it works as expected FTDCCollectorCollection rotate; auto swMgr = FTDCFileManager::create(&c, dir, &rotate, client); ASSERT_OK(swMgr.getStatus()); auto mgr = std::move(swMgr.getValue()); // Test a large numbers of zeros, and incremental numbers in a full buffer for (int j = 0; j < 4; j++) { ASSERT_OK(mgr->writeSampleAndRotateIfNeeded(client, BSON("name" << "joe" << "key1" << 3230792343LL << "key2" << 235135), Date_t())); for (size_t i = 0; i <= FTDCConfig::kMaxSamplesPerArchiveMetricChunkDefault - 2; i++) { ASSERT_OK( mgr->writeSampleAndRotateIfNeeded( client, BSON("name" << "joe" << "key1" << static_cast<long long int>(i * j * 37) << "key2" << static_cast<long long int>(i * (645 << j))), Date_t())); } ASSERT_OK(mgr->writeSampleAndRotateIfNeeded(client, BSON("name" << "joe" << "key1" << 34 << "key2" << 45), Date_t())); // Add Value ASSERT_OK(mgr->writeSampleAndRotateIfNeeded(client, BSON("name" << "joe" << "key1" << 34 << "key2" << 45), Date_t())); } mgr->close(); auto swFile = mgr->generateArchiveFileName(dir, "0test-crash"); ASSERT_OK(swFile); std::ofstream stream(swFile.getValue().c_str()); // This test case caused us to allocate more memory then the size of the file the first time // I tried it stream << "Hello World"; stream.close(); } }