/** * Converts all inodes in the inodes-dir (fomerly 'entries') to the new format and stores * into the correct dir. */ bool Upgrade::initInodesBackupDir(std::string storageDir) { const char* logContext = "initialize the entries backup dir"; this->inodesBackupPath = storageDir + "/" META_INODES_SUBDIR_NAME_OLD META_UPGRADE_BACKUP_EXT; if (!doMkDir(inodesBackupPath) ) { LogContext(logContext).logErr("Failed to create inodes backup dir. Aborting!"); return false; } // create inode backup hash subdirs for(unsigned i=0; i < HASHDIRS_NUM_OLD; i++) { std::string subDirHash = StringTk::uintToHexStr(i); std::string subdirPath = inodesBackupPath + "/" + subDirHash; if (!doMkDir(subdirPath) ) { LogContext(logContext).logErr("Failed to create inodes hash backup dir. Aborting!"); return false; } } return true; }
bool Upgrade::doMkDir(std::string path) { const char* logContext = "mkdir"; int mkDirRes = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IRWXO ); if (mkDirRes) { if (errno == EEXIST) { // path exists already => check whether it is a directory struct stat statStruct; int statRes = stat(path.c_str(), &statStruct); if(statRes || !S_ISDIR(statStruct.st_mode) ) { LogContext(logContext).logErr("mkdir path already exists, but is not a directory: " + path); return false; } return true; // already exists } LogContext(logContext).logErr("Failed to create directory: " + path + ": " + System::getErrString() ); return false; } return true; }
void MsgHelperRepair::createContDirs(Node* node, FsckDirInodeList* inodes, StringList* failedCreates) { const char* logContext = "MsgHelperRepair (createContDirs)"; // create a string list with the IDs StringList directoryIDs; for (FsckDirInodeListIter iter = inodes->begin(); iter != inodes->end(); iter++) { directoryIDs.push_back(iter->getID()); } bool commRes; char *respBuf = NULL; NetMessage *respMsg = NULL; CreateEmptyContDirsMsg createContDirsMsg(&directoryIDs); commRes = MessagingTk::requestResponse(node, &createContDirsMsg, NETMSGTYPE_CreateEmptyContDirsResp, &respBuf, &respMsg); if ( commRes ) { CreateEmptyContDirsRespMsg* createContDirsRespMsg = (CreateEmptyContDirsRespMsg*) respMsg; // parse failed inserts createContDirsRespMsg->parseFailedIDs(failedCreates); SAFE_FREE(respBuf); SAFE_DELETE(respMsg); } else { SAFE_FREE(respBuf); SAFE_DELETE(respMsg); *failedCreates = directoryIDs; LogContext(logContext).logErr( "Communication error occured with node: " + node->getID()); } if ( !failedCreates->empty() ) { for ( StringListIter iter = failedCreates->begin(); iter != failedCreates->end(); iter++ ) { LogContext(logContext).log(Log_CRITICAL, "Failed to create empty content directory. " "directoryID: " + *iter); } } }
void MsgHelperRepair::deleteFiles(Node* node, FsckDirEntryList* dentries, FsckDirEntryList* failedDeletes) { const char* logContext = "MsgHelperRepair (deleteFiles)"; for ( FsckDirEntryListIter iter = dentries->begin(); iter != dentries->end(); iter++ ) { bool commRes; char *respBuf = NULL; NetMessage *respMsg = NULL; EntryInfo parentInfo(node->getNumID(), "", iter->getParentDirID(), "", DirEntryType_DIRECTORY, 0); std::string entryName = iter->getName(); UnlinkFileMsg unlinkFileMsg(&parentInfo, entryName); commRes = MessagingTk::requestResponse(node, &unlinkFileMsg, NETMSGTYPE_UnlinkFileResp, &respBuf, &respMsg); if ( commRes ) { UnlinkFileRespMsg* unlinkFileRespMsg = (UnlinkFileRespMsg*) respMsg; // get result int unlinkRes = unlinkFileRespMsg->getValue(); if ( unlinkRes ) { LogContext(logContext).log(Log_CRITICAL, "Failed to delete file; entryID: " + iter->getID()); failedDeletes->push_back(*iter); } SAFE_FREE(respBuf); SAFE_DELETE(respMsg); } else { SAFE_FREE(respBuf); SAFE_DELETE(respMsg); failedDeletes->push_back(*iter); LogContext(logContext).logErr("Communication error occured with node: " + node->getID()); } } }
void MsgHelperRepair::linkToLostAndFound(Node* lostAndFoundNode, EntryInfo* lostAndFoundInfo, FsckFileInodeList* fileInodes, FsckFileInodeList* failedInodes, FsckDirEntryList* createdDentries) { const char* logContext = "MsgHelperRepair (linkToLostAndFound)"; bool commRes; char *respBuf = NULL; NetMessage *respMsg = NULL; LinkToLostAndFoundMsg linkToLostAndFoundMsg(lostAndFoundInfo, fileInodes); commRes = MessagingTk::requestResponse(lostAndFoundNode, &linkToLostAndFoundMsg, NETMSGTYPE_LinkToLostAndFoundResp, &respBuf, &respMsg); if ( commRes ) { LinkToLostAndFoundRespMsg* linkToLostAndFoundRespMsg = (LinkToLostAndFoundRespMsg*) respMsg; // parse failed inserts linkToLostAndFoundRespMsg->parseFailedInodes(failedInodes); // parse created dentries linkToLostAndFoundRespMsg->parseCreatedDirEntries(createdDentries); SAFE_FREE(respBuf); SAFE_DELETE(respMsg); } else { SAFE_FREE(respBuf); SAFE_DELETE(respMsg); *failedInodes = *fileInodes; LogContext(logContext).logErr("Communication error occured with node: " + lostAndFoundNode->getID()); } if (! failedInodes->empty()) { for (FsckFileInodeListIter iter = failedInodes->begin(); iter != failedInodes->end(); iter++) { LogContext(logContext).log(Log_CRITICAL, "Failed to link file inode to lost+found. " "entryID: " + iter->getID()); } } }
void MsgHelperRepair::createDefDirInodes(Node* node, StringList* inodeIDs, FsckDirInodeList* createdInodes) { const char* logContext = "MsgHelperRepair (createDefDirInodes)"; StringList failedInodeIDs; bool commRes; char *respBuf = NULL; NetMessage *respMsg = NULL; CreateDefDirInodesMsg createDefDirInodesMsgEx(inodeIDs); commRes = MessagingTk::requestResponse(node, &createDefDirInodesMsgEx, NETMSGTYPE_CreateDefDirInodesResp, &respBuf, &respMsg); if ( commRes ) { CreateDefDirInodesRespMsg* createDefDirInodesRespMsg = (CreateDefDirInodesRespMsg*) respMsg; // parse failed creates createDefDirInodesRespMsg->parseFailedInodeIDs(&failedInodeIDs); // parse created inodes createDefDirInodesRespMsg->parseCreatedInodes(createdInodes); SAFE_FREE(respBuf); SAFE_DELETE(respMsg); } else { SAFE_FREE(respBuf); SAFE_DELETE(respMsg); failedInodeIDs = *inodeIDs; LogContext(logContext).logErr("Communication error occured with node: " + node->getID()); } if (! failedInodeIDs.empty()) { for (StringListIter iter = failedInodeIDs.begin(); iter != failedInodeIDs.end(); iter++) { LogContext(logContext).log(Log_CRITICAL, "Failed to create default directory inode on " "metadata node: " + node->getID() + " entryID: " + *iter); } } }
FhgfsOpsErr MirrorMetadataWork::communicate() { const char* logContext = "Mirror metadata work"; App* app = Program::getApp(); FhgfsOpsErr remoteRes; // prepare request MirrorMetadataMsgEx mirrorMsg(taskList, taskListNumElems, taskListSerialLen); RequestResponseArgs rrArgs(NULL, &mirrorMsg, NETMSGTYPE_MirrorMetadataResp); RequestResponseNode rrNode(nodeID, app->getMetaNodes() ); rrNode.setTargetStates(app->getMetaStateStore() ); // send request to node and receive response FhgfsOpsErr requestRes = MessagingTk::requestResponseNode(&rrNode, &rrArgs); if(unlikely(requestRes != FhgfsOpsErr_SUCCESS) ) { // communication error LogContext(logContext).log(Log_WARNING, "Communication with metadata server failed. " "nodeID: " + StringTk::uintToStr(nodeID) ); return requestRes; } // correct response type received MirrorMetadataRespMsg* mirrorRespMsg = (MirrorMetadataRespMsg*)rrArgs.outRespMsg; remoteRes = mirrorRespMsg->getResult(); if(unlikely(remoteRes != FhgfsOpsErr_SUCCESS) ) { // server returned an error LogContext(logContext).log(Log_WARNING, "Metadata mirroring failed on server: " + StringTk::uintToStr(nodeID) + "; " "Error: " + FhgfsOpsErrTk::toErrString(remoteRes) + "; " "NumTasks: " + StringTk::uintToStr(taskList->size() ) ); } else { // mirroring successful LOG_DEBUG(logContext, Log_DEBUG, "Metadata mirroring successful on server: " + StringTk::uintToStr(nodeID) + "; " "NumTasks: " + StringTk::uintToStr(taskList->size() ) ); } return remoteRes; }
LogContext AllocStack::log() const { if (_logs.empty()) { return LogContext(top()); } else { return _logs.get(); } }
void InodeFileStore::clearStoreUnlocked() { const char* logContext = "FileStore::clearStoreUnlocked"; App* app = Program::getApp(); LOG_DEBUG(logContext, Log_DEBUG, std::string("# of loaded entries to be cleared: ") + StringTk::intToStr(inodes.size() ) ); IGNORE_UNUSED_VARIABLE(logContext); for(InodeMapIter iter = inodes.begin(); iter != inodes.end(); iter++) { FileInode* file = iter->second->getReferencedObject(); if(unlikely(file->getNumSessionsAll() ) ) { // check whether file was still open LOG_DEBUG(logContext, Log_DEBUG, std::string("File was still open during shutdown: ") + file->getEntryID() + "; # of sessions: " + StringTk::intToStr(file->getNumSessionsAll() ) ); if (!app->getSelfTerminate() ) LogContext(logContext).logBacktrace(); } delete(iter->second); } inodes.clear(); }
/** * Note: This works by serializing the original and marking the object unreferencable (exclusive), * so remember to call movingCancel() or movingComplete() * * @param buf target buffer for serialization (only valid if success is returned) * @param bufLen must be at least META_SERBUF_SIZE * @param outUsedBufLen the used bufLen */ FhgfsOpsErr InodeFileStore::moveRemoteBegin(EntryInfo* entryInfo, char* buf, size_t bufLen, size_t* outUsedBufLen) { const char* logContext = "Serialize Inode"; FhgfsOpsErr retVal = FhgfsOpsErr_PATHNOTEXISTS; if(bufLen < META_SERBUF_SIZE) { LogContext(logContext).log(Log_ERR, "Error: Buffer too small!"); return FhgfsOpsErr_INTERNAL; } SafeRWLock safeLock(&rwlock, SafeRWLock_WRITE); // L O C K FileInode* inode; retVal = getUnreferencedInodeUnlocked(entryInfo, &inode); // does not set refCount if (retVal == FhgfsOpsErr_SUCCESS) { /* We got an inode, which is in the map, but is unreferenced. Now we are going to exclusively * lock it. If another thread should try to reference it, it will fail due to this lock. */ *outUsedBufLen = inode->serializeMetaData(buf); inode->setExclusive(true); } safeLock.unlock(); // U N L O C K return retVal; }
bool MkLocalDirMsgEx::processIncoming(struct sockaddr_in* fromAddr, Socket* sock, char* respBuf, size_t bufLen, HighResolutionStats* stats) { const char* logContext = "MkLocalDirMsg incoming"; EntryInfo* entryInfo = getEntryInfo(); std::string peer = fromAddr ? Socket::ipaddrToStr(&fromAddr->sin_addr) : sock->getPeername(); LOG_DEBUG(logContext, 4, std::string("Received a MkLocalDirMsg from: ") + peer + std::string(" entryID: ") + entryInfo->getEntryID() + std::string(" entryName: ") + entryInfo->getFileName() ); IGNORE_UNUSED_VARIABLE(logContext); IGNORE_UNUSED_VARIABLE(entryInfo); FhgfsOpsErr mkRes = FhgfsOpsErr_INTERNAL; StripePattern* pattern = createPattern(); if(unlikely(pattern->getPatternType() == STRIPEPATTERN_Invalid) ) LogContext(logContext).logErr("Received an invalid stripe pattern from: " + peer); else mkRes = mkLocalDir(pattern); delete(pattern); MkLocalDirRespMsg respMsg(mkRes); respMsg.serialize(respBuf, bufLen); sock->sendto(respBuf, respMsg.getMsgLength(), 0, (struct sockaddr*)fromAddr, sizeof(struct sockaddr_in) ); return true; }
bool Upgrade::migrateInode(std::string inodeID, std::string inodePath, std::string subDirHash) { const char* logContext = "migrage Inode"; bool isDirInode; unsigned strLen = inodeID.length(); std::string suffix = inodeID.substr(strLen - 2, SUFFIX_LENGTH); if (suffix.compare("-d") == 0 ) isDirInode = true; else if (suffix.compare("-f") == 0) isDirInode = false; else { LogContext(logContext).logErr(""); LogContext(logContext).logErr("Inode is neither a dir nor a directory: " + inodePath ); this->allOK = false; return false; } std::string idWithOutSuffix = inodeID; idWithOutSuffix.resize(strLen - 2); bool migrateRes; if (isDirInode) { // Hmm, shall we really do anything here? Actually migrate migrateDentries() is a better // place to handle DirInodes. If there is no contents dir, this DirInode can be deleted, // as there are no entries... DirInode* inode = NULL; migrateRes = migrateDirInode(idWithOutSuffix, &inode); if (migrateRes == true) backupOrDeleteDirInode(inode); SAFE_DELETE(inode); return migrateRes; } else migrateRes = migrateFileInode(idWithOutSuffix); return migrateRes; }
void MsgHelperRepair::deleteFileInodes(Node* node, FsckFileInodeList& inodes, StringList& failedDeletes) { const char* logContext = "MsgHelperRepair (deleteFileInodes)"; StringList entryIDList; DirEntryTypeList entryTypeList; for ( FsckFileInodeListIter iter = inodes.begin(); iter != inodes.end(); iter++ ) { entryIDList.push_back(iter->getID()); entryTypeList.push_back(DirEntryType_REGULARFILE); } bool commRes; char *respBuf = NULL; NetMessage *respMsg = NULL; RemoveInodesMsg removeInodesMsg(&entryIDList, &entryTypeList); commRes = MessagingTk::requestResponse(node, &removeInodesMsg, NETMSGTYPE_RemoveInodesResp, &respBuf, &respMsg); if ( commRes ) { RemoveInodesRespMsg* removeInodesRespMsg = (RemoveInodesRespMsg*) respMsg; removeInodesRespMsg->parseFailedEntryIDList(&failedDeletes); for ( StringListIter iter = failedDeletes.begin(); iter != failedDeletes.end(); iter++ ) { LogContext(logContext).logErr( "Failed to delete file inode; nodeID: " + StringTk::uintToStr(node->getNumID()) + "; entryID: " + *iter); } } else { LogContext(logContext).logErr("Communication error occured with node: " + node->getID()); failedDeletes = entryIDList; } SAFE_FREE(respBuf); SAFE_DELETE(respMsg); }
void MsgHelperRepair::recreateDentries(Node* node, FsckFsIDList* fsIDs, FsckFsIDList* failedCreates, FsckDirEntryList* createdDentries, FsckFileInodeList* createdInodes) { const char* logContext = "MsgHelperRepair (recreateDentries)"; bool commRes; char *respBuf = NULL; NetMessage *respMsg = NULL; RecreateDentriesMsg recreateDentriesMsg(fsIDs); commRes = MessagingTk::requestResponse(node, &recreateDentriesMsg, NETMSGTYPE_RecreateDentriesResp, &respBuf, &respMsg); if ( commRes ) { RecreateDentriesRespMsg* recreateDentriesMsg = (RecreateDentriesRespMsg*) respMsg; // parse failed creates recreateDentriesMsg->parseFailedCreates(failedCreates); recreateDentriesMsg->parseCreatedDentries(createdDentries); recreateDentriesMsg->parseCreatedInodes(createdInodes); SAFE_FREE(respBuf); SAFE_DELETE(respMsg); } else { SAFE_FREE(respBuf); SAFE_DELETE(respMsg); *failedCreates = *fsIDs; LogContext(logContext).logErr("Communication error occured with node: " + node->getID()); } if ( !failedCreates->empty() ) { for ( FsckFsIDListIter iter = failedCreates->begin(); iter != failedCreates->end(); iter++ ) { LogContext(logContext).log(Log_CRITICAL, "Failed to recreate dentry." " entryID: " + iter->getID()); } } }
void InternodeSyncer::updateTargetBuddyCapacityPools() { App* app = Program::getApp(); MirrorBuddyGroupMapper* buddyMapper = app->getMirrorBuddyGroupMapper(); TargetCapacityPools* targetPools = app->getStorageCapacityPools(); NodeCapacityPools* buddyPools = app->getStorageBuddyCapacityPools(); UInt16Set listNormal; // new "normal" buddy group pool list UInt16Set listLow; UInt16Set listEmergency; UInt16List buddyGroupIDs; MirrorBuddyGroupList buddyGroups; buddyMapper->getMappingAsLists(buddyGroupIDs, buddyGroups); UInt16ListConstIter buddyGroupIDIter = buddyGroupIDs.begin(); MirrorBuddyGroupListCIter buddyGroupIter = buddyGroups.begin(); // walk all mapped buddy groups, add them to buddy pools based on worst buddy pool of any buddy for( ; buddyGroupIDIter != buddyGroupIDs.end(); buddyGroupIDIter++, buddyGroupIter++) { CapacityPoolType primaryPoolType; bool primaryFound = targetPools->getPoolAssignment(buddyGroupIter->firstTargetID, &primaryPoolType); if(!primaryFound) continue; // can't make a pool decision if a buddy does not exist CapacityPoolType secondaryPoolType; bool secondaryFound = targetPools->getPoolAssignment(buddyGroupIter->secondTargetID, &secondaryPoolType); if(!secondaryFound) continue; // can't make a pool decision if a buddy does not exist CapacityPoolType groupPoolType = BEEGFS_MAX(primaryPoolType, secondaryPoolType); if(groupPoolType == CapacityPool_NORMAL) listNormal.insert(*buddyGroupIDIter); else if(groupPoolType == CapacityPool_LOW) listLow.insert(*buddyGroupIDIter); else if(groupPoolType == CapacityPool_EMERGENCY) listEmergency.insert(*buddyGroupIDIter); else { // should never happen LogContext(__func__).logErr( "Skipping invalid groupPoolType: " + StringTk::intToStr(groupPoolType) ); } } // apply new pools buddyPools->syncPoolsFromSets(listNormal, listLow, listEmergency); }
/** * Get the difference vector of op counters between previous and current values * NOTE: The result MUST be free'ed from the caller. */ UInt64Vector* ClientStatsDiff::newDiffVector(uint64_t IP) { LogContext log = LogContext("ClientStatsDiff ( new diff vector)"); UInt64Vector* currentVec = ClientStats::getVectorFromMap(this->currentVecMap, IP); if (!currentVec) { struct in_addr in_addr = { (in_addr_t)IP }; std::string logMessage("BUG: Missing vector for IP" + Socket::ipaddrToStr(&in_addr) ); log.logErr(logMessage); std::cerr << logMessage << std::endl; return NULL; } UInt64Vector* diffVec = new UInt64Vector(*currentVec); // copy of the current values first UInt64Vector* oldVec = ClientStats::getVectorFromMap(this->oldVecMap, IP); if (!oldVec) return diffVec; // IP just did not do any IO last time, so old values are zero uint64_t oldIP = oldVec->at(OPCOUNTERVECTOR_POS_IP); uint64_t curIP = currentVec->at(OPCOUNTERVECTOR_POS_IP); if (oldIP != curIP) { struct in_addr cur_addr = { (in_addr_t)curIP }; struct in_addr old_addr = { (in_addr_t)oldIP }; std::string logMessage("Bug: IP mismatch between old and current vector " + Socket::ipaddrToStr(&old_addr) + "vs. " + Socket::ipaddrToStr(&cur_addr) ); log.logErr(logMessage); std::cerr << logMessage << std::endl; return NULL; } /* vector length might be different, for example after an update to a different FhGFS version * on a server. So we need to check for it and to unify vector length. */ int maxVecSize = BEEGFS_MAX(currentVec->size(), oldVec->size() ); currentVec->resize(maxVecSize, 0); oldVec->resize(maxVecSize, 0); // set iter to first counter UInt64VectorIter diffIter = diffVec->begin() + OPCOUNTERVECTOR_POS_FIRSTCOUNTER; UInt64VectorIter oldIter = oldVec->begin() + OPCOUNTERVECTOR_POS_FIRSTCOUNTER; do { // no checks required here, as we already checked the vector sizes above *diffIter -= *oldIter; oldIter++; diffIter++; } while (oldIter != oldVec->end() ); return diffVec; }
void MsgHelperRepair::correctInodeOwnersInDentry(Node* node, FsckDirEntryList* dentries, FsckDirEntryList* failedCorrections) { const char* logContext = "MsgHelperRepair (correctInodeOwnersInDentry)"; bool commRes; char *respBuf = NULL; NetMessage *respMsg = NULL; FixInodeOwnersInDentryMsg fixInodeOwnersMsg(dentries); commRes = MessagingTk::requestResponse(node, &fixInodeOwnersMsg, NETMSGTYPE_FixInodeOwnersInDentryResp, &respBuf, &respMsg); if ( commRes ) { FixInodeOwnersInDentryRespMsg* fixInodeOwnersRespMsg = (FixInodeOwnersInDentryRespMsg*) respMsg; // parse failed corrections fixInodeOwnersRespMsg->parseFailedEntries(failedCorrections); SAFE_FREE(respBuf); SAFE_DELETE(respMsg); } else { SAFE_FREE(respBuf); SAFE_DELETE(respMsg); *failedCorrections = *dentries; LogContext(logContext).logErr("Communication error occured with node: " + node->getID()); } if (! failedCorrections->empty()) { for (FsckDirEntryListIter iter = failedCorrections->begin(); iter != failedCorrections->end(); iter++) { LogContext(logContext).log(Log_CRITICAL, "Failed to correct inode owner information in " "dentry on on metadata node: " + node->getID() + " entryID: " + iter->getID()); } } }
void MsgHelperRepair::changeStripeTarget(Node* node, FsckFileInodeList* inodes, uint16_t targetID, uint16_t newTargetID, FsckFileInodeList* failedInodes) { const char* logContext = "MsgHelperRepair (changeStripeTarget)"; bool commRes; char *respBuf = NULL; NetMessage *respMsg = NULL; ChangeStripeTargetMsg changeStripeTargetMsg(inodes, targetID, newTargetID); commRes = MessagingTk::requestResponse(node, &changeStripeTargetMsg, NETMSGTYPE_ChangeStripeTargetResp, &respBuf, &respMsg); if ( commRes ) { ChangeStripeTargetRespMsg* changeStripeTargetRespMsg = (ChangeStripeTargetRespMsg*) respMsg; // parse failed update changeStripeTargetRespMsg->parseFailedInodes(failedInodes); SAFE_FREE(respBuf); SAFE_DELETE(respMsg); } else { SAFE_FREE(respBuf); SAFE_DELETE(respMsg); *failedInodes = *inodes; LogContext(logContext).logErr("Communication error occured with node: " + node->getID()); } if ( !failedInodes->empty() ) { for ( FsckFileInodeListIter iter = failedInodes->begin(); iter != failedInodes->end(); iter++ ) { LogContext(logContext).log(Log_CRITICAL, "Failed to change stripe pattern of inode." " entryID: " + iter->getID()); } } }
void MsgHelperRepair::updateDirAttribs(Node* node, FsckDirInodeList* inodes, FsckDirInodeList* failedUpdates) { const char* logContext = "MsgHelperRepair (updateDirAttribs)"; bool commRes; char *respBuf = NULL; NetMessage *respMsg = NULL; UpdateDirAttribsMsg updateDirAttribsMsg(inodes); commRes = MessagingTk::requestResponse(node, &updateDirAttribsMsg, NETMSGTYPE_UpdateDirAttribsResp, &respBuf, &respMsg); if ( commRes ) { UpdateDirAttribsRespMsg* updateDirAttribsRespMsg = (UpdateDirAttribsRespMsg*) respMsg; // parse failed update updateDirAttribsRespMsg->parseFailedInodes(failedUpdates); SAFE_FREE(respBuf); SAFE_DELETE(respMsg); } else { SAFE_FREE(respBuf); SAFE_DELETE(respMsg); *failedUpdates = *inodes; LogContext(logContext).logErr("Communication error occured with node: " + node->getID()); } if ( !failedUpdates->empty() ) { for ( FsckDirInodeListIter iter = failedUpdates->begin(); iter != failedUpdates->end(); iter++ ) { LogContext(logContext).log(Log_CRITICAL, "Failed to update attributes of directory inode." " entryID: " + iter->getID()); } } }
void MsgHelperRepair::deleteDanglingDirEntries(Node *node, FsckDirEntryList* dentries, FsckDirEntryList* failedDeletes) { const char* logContext = "MsgHelperRepair (deleteDanglingDirEntries)"; bool commRes; char *respBuf = NULL; NetMessage *respMsg = NULL; DeleteDirEntriesMsg deleteDirEntriesMsg(dentries); commRes = MessagingTk::requestResponse(node, &deleteDirEntriesMsg, NETMSGTYPE_DeleteDirEntriesResp, &respBuf, &respMsg); if ( commRes ) { DeleteDirEntriesRespMsg* deleteDirEntriesRespMsg = (DeleteDirEntriesRespMsg*) respMsg; // parse failed directory entries deleteDirEntriesRespMsg->parseFailedEntries(failedDeletes); if (! failedDeletes->empty()) { for (FsckDirEntryListIter iter = failedDeletes->begin(); iter != failedDeletes->end(); iter++) { LogContext(logContext).log(Log_CRITICAL, "Failed to delete directory entry from " "metadata node: " + node->getID() + " entryID: " + iter->getID()); } } SAFE_FREE(respBuf); SAFE_DELETE(respMsg); } else { SAFE_FREE(respBuf); SAFE_DELETE(respMsg); *failedDeletes = *dentries; LogContext(logContext).logErr("Communication error occured with node: " + node->getID()); } }
void MsgHelperRepair::deleteChunks(Node* node, FsckChunkList* chunks, FsckChunkList* failedDeletes) { const char* logContext = "MsgHelperRepair (deleteChunks)"; bool commRes; char *respBuf = NULL; NetMessage *respMsg = NULL; DeleteChunksMsg deleteChunksMsg(chunks); commRes = MessagingTk::requestResponse(node, &deleteChunksMsg, NETMSGTYPE_DeleteChunksResp, &respBuf, &respMsg); if ( commRes ) { DeleteChunksRespMsg* deleteChunksRespMsg = (DeleteChunksRespMsg*) respMsg; // parse failed deletes deleteChunksRespMsg->parseFailedChunks(failedDeletes); if (! failedDeletes->empty()) { for (FsckChunkListIter iter = failedDeletes->begin(); iter != failedDeletes->end(); iter++) { LogContext(logContext).log(Log_CRITICAL, "Failed to delete chunk entry. targetID: " + StringTk::uintToStr(iter->getTargetID()) + " chunkID: " + iter->getID()); } } SAFE_FREE(respBuf); SAFE_DELETE(respMsg); } else { SAFE_FREE(respBuf); SAFE_DELETE(respMsg); *failedDeletes = *chunks; LogContext(logContext).logErr("Communication error occured with node: " + node->getID()); } }
/** * Reads the contents of an inode file (file or dir inode) directly from disk * * Note: Don't call this directly, use the wrapper loadInodeFromFile(). * Note: No locking at all * Note: currently unused * * @param metaFilename the complete path to the inode file * @param outFileInode the inode contents (must be deleted by the caller), or NULL if inode is not * a file inode * @param outDirInode the inode contents (must be deleted by the caller), or NULL if inode is not * a dir inode * @return the entry type of the inode or DirEntryType_INVALID if an error occured */ DirEntryType StorageTkEx::readInodeFromFileContentsUnlocked(std::string& metaFilename, FileInode** outFileInode, DirInode** outDirInode) { const char* logContext = "MetaStore (load from file contents)"; DirEntryType retVal = DirEntryType_INVALID; int openFlags = O_NOATIME | O_RDONLY; int fd = open(metaFilename.c_str(), openFlags, 0); if(fd == -1) { // open failed if(errno != ENOENT) LogContext(logContext).logErr("Unable to open inode file: " + metaFilename + ". " + "SysErr: " + System::getErrString() ); return DirEntryType_INVALID; } char* buf = (char*)malloc(META_SERBUF_SIZE); int readRes = read(fd, buf, META_SERBUF_SIZE); if(readRes <= 0) { // reading failed LogContext(logContext).logErr("Unable to read inode file: " + metaFilename + ". " + "SysErr: " + System::getErrString() ); } else { retVal = DiskMetaData::deserializeInode(buf, outFileInode, outDirInode); if (unlikely(retVal == DirEntryType_INVALID)) { // deserialization failed LogContext(logContext).logErr("Unable to deserialize inode in file: " + metaFilename); } } free(buf); close(fd); return retVal; }
bool Upgrade::loadIDMap(std::string mapFileName, StringUnsignedMap* outIdMap) { const char* logContext = "Load IP map file"; std::ifstream fis(mapFileName.c_str() ); if(!fis.is_open() || fis.fail() ) { LogContext(logContext).logErr("Failed to open ID-map-file: " + System::getErrString() ); return false; } bool retVal = true; char line[STORAGETK_FILE_MAX_LINE_LENGTH]; while(!fis.eof() && !fis.fail() ) { fis.getline(line, STORAGETK_FILE_MAX_LINE_LENGTH); std::string trimmedLine = StringTk::trim(line); if(trimmedLine.length() && (trimmedLine[0] != STORAGETK_FILE_COMMENT_CHAR) ) { unsigned numID; char stringID[513]; int scanRes = sscanf(trimmedLine.c_str(), "%48s %u", stringID, &numID); if (scanRes == ID_MAP_FILE_COLUMS) outIdMap->insert(StringUnsignedMapVal(stringID, numID) ); else { LogContext(logContext).logErr("Invalid line in map file (" + mapFileName + ")" + std::string(" Line: ") + line); break; retVal = false; } } } fis.close(); return retVal; }
bool AdjustChunkPermissionsMsgEx::sendSetAttrMsg(std::string& entryID, unsigned userID, unsigned groupID, PathInfo* pathInfo, StripePattern* pattern) { const char* logContext = "AdjustChunkPermissionsMsgEx::sendSetAttrMsg"; MultiWorkQueue* slaveQueue = Program::getApp()->getCommSlaveQueue(); int validAttribs = SETATTR_CHANGE_USERID | SETATTR_CHANGE_GROUPID; // only interested in these SettableFileAttribs attribs; attribs.userID = userID; attribs.groupID = groupID; const UInt16Vector* stripeTargets = pattern->getStripeTargetIDs(); size_t numTargetWorks = stripeTargets->size(); FhgfsOpsErrVec nodeResults(numTargetWorks); SynchronizedCounter counter; // generate work for storage targets... for(size_t i=0; i < numTargetWorks; i++) { SetChunkFileAttribsWork* work = new SetChunkFileAttribsWork( entryID, validAttribs, &attribs, false, pattern, (*stripeTargets)[i], pathInfo, NULL, &(nodeResults[i]), &counter); work->setQuotaChown(true); work->setMsgUserID(getMsgHeaderUserID() ); slaveQueue->addDirectWork(work); } // wait for work completion... counter.waitForCount(numTargetWorks); // check target results... for(size_t i=0; i < numTargetWorks; i++) { if(unlikely(nodeResults[i] != FhgfsOpsErr_SUCCESS) ) { LogContext(logContext).log(Log_WARNING, "Problems occurred during setting of chunk file attribs. " "fileID: " + entryID ); return false; } } return true; }
/** * Reads the contents of an inode file (file or dir inode) directly from disk * * Note: Don't call this directly, use the wrapper loadInodeFromFile(). * Note: No locking at all * Note: currently unused * * @param metaFilename the complete path to the inode file * @param outFileInode the inode contents (must be deleted by the caller), or NULL if inode is not * a file inode * @param outDirInode the inode contents (must be deleted by the caller), or NULL if inode is not * a dir inode * @return the entry type of the inode or DirEntryType_INVALID if an error occured */ DirEntryType StorageTkEx::readInodeFromFileXAttrUnlocked(std::string& metaFilename, FileInode** outFileInode, DirInode** outDirInode) { const char* logContext = "MetaStore (load from xattr file)"; DirEntryType retVal = DirEntryType_INVALID; char *buf = (char*) malloc(META_SERBUF_SIZE); ssize_t getRes = getxattr(metaFilename.c_str(), META_XATTR_FILE_NAME, buf, META_SERBUF_SIZE); if ( getRes > 0 ) { // we got something => deserialize it retVal = DiskMetaData::deserializeInode(buf, outFileInode, outDirInode); if ( unlikely(retVal == DirEntryType_INVALID) ) { // deserialization failed LogContext(logContext).logErr("Unable to deserialize metadata in file: " + metaFilename); goto error_freebuf; } } else if ( (getRes == -1) && (errno == ENOENT) ) { // file does not exist LOG_DEBUG_CONTEXT(LogContext(logContext), Log_DEBUG, "Inode file does not exist: " + metaFilename + ". " + "SysErr: " + System::getErrString()); } else { // unhandled error LogContext(logContext).logErr( "Unable to open/read inode file: " + metaFilename + ". " + "SysErr: " + System::getErrString()); } error_freebuf: free(buf); return retVal; }
/** * Delete the inode on disk or move it into the backup dir. * */ bool Upgrade::backupOrDeleteDirInode(DirInode* inode) { App* app = Program::getApp(); bool deleteOldEntries = app->getConfig()->getDeleteOldFiles(); bool retVal = true; if (deleteOldEntries) { const char* logContext = "Delete DirInode"; int unlinkRes = unlink(inode->getPathToDirInode() ); if (unlinkRes) { retVal = false; this->allOK = false; LogContext(logContext).logErr(""); LogContext(logContext).logErr(std::string("Failed to delete old DirInode: ") + inode->getPathToDirInode() + std::string(" :") + System::getErrString() ); } } else { // move to backup dir const char* logContext = "Backup DirInode"; std::string inodeBackupDir = this->inodesBackupPath + inode->getOldHashDirPath(); int renameRes = rename(inode->getPathToDirInode(), inodeBackupDir.c_str() ); if (renameRes && errno != EEXIST) { retVal = false; this->allOK = false; LogContext(logContext).logErr(""); LogContext(logContext).logErr(std::string("Failed to rename DirInode to backup dir: ") + inode->getPathToDirInode() + std::string(": ") + System::getErrString() ); } } return retVal; }
/** * Wrapper for pools->addOrUpdate (metadata node version) which also produces a log message. * @param nodeIDStr node ID as a string for logging * @param reason reason the target has been put into that pool (for logging) * @returns true if the target has been assigned to the pool, false if it already was in that pool. */ bool InternodeSyncer::assignNodeToPool(NodeCapacityPools* pools, uint16_t nodeID, CapacityPoolType pool, const std::string& reason) { const char* logContext = "Assign node to capacity pool"; bool updateRes = pools->addOrUpdate(nodeID, pool); if(updateRes) LogContext(logContext).log(Log_WARNING, "Metadata node capacity pool assignment updated. " "NodeID: " + StringTk::uintToStr(nodeID) + "; " "Pool: " + NodeCapacityPools::poolTypeToStr(pool) + "; " "Reason: " + reason); return updateRes; }
/** * Get the vector that has the statistics from the server. * * @param requestPerUserStats true to request per-user statistics instead of default per-client * statistics. */ bool ClientStatsHelper::getIOVec(Node* node, uint64_t cookieIP, bool requestPerUserStats, UInt64Vector* outVec) { LogContext log = LogContext("ClientStats (get IO vector) "); bool retVal = false; bool commRes; char* respBuf = NULL; NetMessage* respMsg = NULL; GetClientStatsRespMsg* respMsgCast; bool parseRes; // we start to request a message for cookieIP=0, so no cookie set GetClientStatsMsg getStatsMsg(cookieIP); if(requestPerUserStats) getStatsMsg.addMsgHeaderFeatureFlag(GETCLIENTSTATSMSG_FLAG_PERUSERSTATS); // request/response commRes = MessagingTk::requestResponse( node, &getStatsMsg, NETMSGTYPE_GetClientStatsResp, &respBuf, &respMsg); if(!commRes) { std::string logMessage("Communication with node failed: " + node->getNodeIDWithTypeStr() ); log.logErr(logMessage); std::cerr << logMessage << std::endl; goto err_cleanup; } respMsgCast = ((GetClientStatsRespMsg*)respMsg); parseRes = respMsgCast->parseStatsVector(outVec); // data copied into vec, so we may free respMsg if (!parseRes) { std::string logMessage("Parsing data from server failed: " + node->getNodeIDWithTypeStr() ); log.logErr(logMessage); std::cerr << logMessage << std::endl; retVal = false; goto err_cleanup; } retVal = true; err_cleanup: SAFE_DELETE(respMsg); SAFE_FREE(respBuf); return retVal; }
/** * Note: remember to call releaseNode() * * @return NULL if no such node exists */ Node* NodeStoreServers::referenceNode(uint16_t id) { // check for invalid id 0 #ifdef FHGFS_DEBUG if(!id) LogContext(__func__).log(Log_CRITICAL, "BUG?: Attempt to reference numeric node ID '0'"); #endif // FHGFS_DEBUG SafeMutexLock mutexLock(&mutex); // L O C K Node* node = NULL; if(localNode && (id == localNode->getNumID() ) ) node = localNode; else { // search in active nodes map NodeMapIter iter = activeNodes.find(id); if(iter != activeNodes.end() ) { // found it NodeReferencer* nodeRefer = iter->second; node = nodeRefer->reference(); // check for unusually high reference count #ifdef FHGFS_DEBUG if(nodeRefer->getRefCount() > 100) LogContext(__func__).log(Log_CRITICAL, std::string("WARNING: Lots of references to node (=> leak?): ") + node->getID() + " ref count: " + StringTk::intToStr(nodeRefer->getRefCount() ) ); #endif // FHGFS_DEBUG } } mutexLock.unlock(); // U N L O C K return node; }
/** * Wrapper for pools->addOrUpdate (storage target ID version) which also produces a log message. * @param nodeIDStr node ID as a string for logging * @param reason reason the target has been put into that pool (for logging) * @returns true if the target has been assigned to the pool, false if it already was in that pool. */ bool InternodeSyncer::assignTargetToPool(TargetCapacityPools* pools, uint16_t targetID, uint16_t nodeID, CapacityPoolType pool, const std::string& reason) { const char* logContext = "Assign target to capacity pool"; bool updateRes = pools->addOrUpdate(targetID, nodeID, pool); if(updateRes) LogContext(logContext).log(Log_WARNING, "Storage target capacity pool assignment updated. " "NodeID: " + StringTk::uintToStr(nodeID) + "; " "TargetID: " + StringTk::uintToStr(targetID) + "; " "Pool: " + TargetCapacityPools::poolTypeToStr(pool) + "; " "Reason: " + reason); return updateRes; }