/* * Save current state for block. If this is the first time saving state for * block, create a new snapshot. Otherwise merge the current state into the * existing snapshot. */ void FrameState::save(Block* block) { auto it = m_snapshots.find(block); if (it != m_snapshots.end()) { merge(it->second); } else { auto& snapshot = m_snapshots[block] = createSnapshot(); snapshot.inlineSavedStates = m_inlineSavedStates; } }
/* * Save current state for block. If this is the first time saving state for * block, create a new snapshot. Otherwise merge the current state into the * existing snapshot. */ void FrameState::save(Block* block) { FTRACE(4, "Saving state for B{}: {}\n", block->id(), show(*this)); auto it = m_snapshots.find(block); if (it != m_snapshots.end()) { merge(it->second); FTRACE(4, "Merged state: {}\n", show(*this)); } else { auto& snapshot = m_snapshots[block] = createSnapshot(); snapshot.inlineSavedStates = m_inlineSavedStates; } }
void FrameState::trackDefInlineFP(const IRInstruction* inst) { auto const target = inst->extra<DefInlineFP>()->target; auto const savedSPOff = inst->extra<DefInlineFP>()->retSPOff; auto const calleeFP = inst->dst(); auto const calleeSP = inst->src(0); auto const savedSP = inst->src(1); // Saved IRBuilder state will include the "return" fp/sp. // Whatever the current fpValue is is good enough, but we have to be // passed in the StkPtr that represents the stack prior to the // ActRec being allocated. m_spOffset = savedSPOff; m_spValue = savedSP; auto const stackValues = collectStackValues(m_spValue, m_spOffset); for (DEBUG_ONLY auto& val : stackValues) { FTRACE(4, " marking caller stack value available: {}\n", val->toString()); } m_inlineSavedStates.emplace_back(createSnapshot()); /* * Set up the callee state. * * We set m_thisIsAvailable to true on any object method, because we * just don't inline calls to object methods with a null $this. */ m_fpValue = calleeFP; m_spValue = calleeSP; m_thisAvailable = target->cls() != nullptr && !target->isStatic(); m_curFunc = target; m_frameSpansCall = false; m_locals.clear(); m_locals.resize(target->numLocals()); }
int syncInit(int cfd, long long *tbytes) { char errmsg[ERRMSG_MAX] = {0}; SyncInit *syncinit; SyncInitResponse response = SYNC_INIT_RESPONSE__INIT; syncinit = (SyncInit *) recvMessage(cfd, SyncInitType, tbytes); if (syncinit == NULL) { errMsg(LOG_ERR, "Could not read initialization message from client."); return -1; } // initial checks // check resource (must match) if (strcmp(syncinit->resource, config.resource) != 0) { snprintf(errmsg, ERRMSG_MAX, "Received resource %s does not match." "local resource %s", syncinit->resource, config.resource); response.continue_ = 0; response.error_message = errmsg; sendMessage(cfd, SyncInitResponseType, &response); return -1; } // check sync-id char lastsyncid[SYNCID_MAX]; char lastsyncidpath[PATH_MAX]; char syncid[SYNCID_MAX]; char syncidpath[PATH_MAX]; // if we receive syncid, we already marked as successfully done // only sending confirmation has failed last time snprintf(lastsyncidpath, PATH_MAX, "%s/%s.syncid.last", config.logdir, config.resource); if (fileExists(lastsyncidpath) && (readSyncId(lastsyncid, lastsyncidpath, SYNCID_MAX) == 0)) { if (lastsyncid == syncinit->sync_id) { // send the confirmation, don't sync response.continue_ = 0; response.has_already_synced = 1; response.already_synced = 1; sendMessage(cfd, SyncInitResponseType, &response); return 0; // no files to be synchronized } } int errflag = 0; // if we can read syncid file, last sync did not finish properly // revert snapshot snprintf(syncidpath, PATH_MAX, "%s/%s.syncid", config.logdir, config.resource); if (fileExists(syncidpath) && (readSyncId(syncid, syncidpath, SYNCID_MAX) == 0)) { if (syncid == syncinit->sync_id) { // TODO: here we should support resume } // revert last snapshot, check for its existence is necessary, but // is done nevertheless if (fileExists(config.snapshot) == 1) { // do as one block, this should not fail, if yes, we are in trouble errMsg(LOG_INFO, "Reverting snapshot."); int ret = 0; ret = deleteSnapshot(config.rootdir); ret |= createSnapshot(config.snapshot, config.rootdir, 0); ret |= deleteSnapshot(config.snapshot); if (ret != 0) { errflag = 1; snprintf(errmsg, ERRMSG_MAX, "Reverting to last snapshot" "has failed."); } } } // create snapshot // snapshot might exists (if last time program crash before sync-id was // written or before it was deleted), but in this case we don't need to // revert it if (!errflag && fileExists(config.snapshot)) { errMsg(LOG_INFO, "Snapshot %s unexpectedly exists, deleting.", config.snapshot); if (deleteSnapshot(config.snapshot) == -1) { errMsg(LOG_ERR, "Could not delete snapshot %s", config.snapshot); errflag = 1; } } if (!errflag && (createSnapshot(config.rootdir, config.snapshot, 1) != 0)) { errMsg(LOG_ERR, "Could not create snapshot %s", config.snapshot); errflag = 1; } // write syncid if (!errflag && (writeSyncId(syncinit->sync_id, syncidpath) != 0)) { errMsg(LOG_ERR, "Could not write sync-id. Stopping."); errflag = 1; } // send response int ret; if (errflag) { response.continue_ = 0; snprintf(errmsg, ERRMSG_MAX, "Error in snapshot operation."); response.error_message = errmsg; ret = -1; } else { response.continue_ = 1; ret = syncinit->number_files; } sync_init__free_unpacked(syncinit, NULL); if (sendMessage(cfd, SyncInitResponseType, &response) == 0) return ret; else return -1; }
TEST_F(SnapshotManagerTests, BasicFunctionality) { if (!snapshotManager) return; // This test is only for engines that DO support SnapshotMangers. // Snapshot variables are named according to the size of the RecordStore at the time of the // snapshot. auto snap0 = prepareAndCreateSnapshot(); insertRecordAndCommit(); auto snap1 = prepareAndCreateSnapshot(); insertRecordAndCommit(); prepareSnapshot(); insertRecordAndCommit(); auto snap2 = createSnapshot(); { auto op = makeOperation(); WriteUnitOfWork wuow(op); insertRecord(op); prepareSnapshot(); // insert should still be invisible. ASSERT_EQ(itCountOn(snapshotOperation), 3); wuow.commit(); } auto snap3 = createSnapshot(); { auto op = makeOperation(); WriteUnitOfWork wuow(op); insertRecord(op); // rolling back wuow } auto snap4 = prepareAndCreateSnapshot(); // If these fail, everything is busted. snapshotManager->setCommittedSnapshot(snap0); ASSERT_EQ(itCountCommitted(), 0); snapshotManager->setCommittedSnapshot(snap1); ASSERT_EQ(itCountCommitted(), 1); // If this fails, the snapshot is from the 'create' time rather than the 'prepare' time. snapshotManager->setCommittedSnapshot(snap2); ASSERT_EQ(itCountCommitted(), 2); // If this fails, the snapshot contains writes that weren't yet committed. snapshotManager->setCommittedSnapshot(snap3); ASSERT_EQ(itCountCommitted(), 3); // This op should keep its original snapshot until abandoned. auto longOp = makeOperation(); ASSERT_OK(longOp->recoveryUnit()->setReadFromMajorityCommittedSnapshot()); ASSERT_EQ(itCountOn(longOp), 3); // If this fails, the snapshot contains writes that were rolled back. snapshotManager->setCommittedSnapshot(snap4); ASSERT_EQ(itCountCommitted(), 4); // If this fails, longOp changed snapshots at an illegal time. ASSERT_EQ(itCountOn(longOp), 3); // If this fails, snapshots aren't preserved while in use. snapshotManager->cleanupUnneededSnapshots(); ASSERT_EQ(itCountOn(longOp), 3); // If this fails, longOp didn't get a new snapshot when it should have. longOp->recoveryUnit()->abandonSnapshot(); ASSERT_EQ(itCountOn(longOp), 4); }
int synchronize(void) { int pidfd; char pidpath[PATH_MAX]; int logfd; char logpath[PATH_MAX]; int newsync = 0; // make sure, that there isn't another client process for this resource // already running snprintf(pidpath, PATH_MAX, "/var/run/syncedfs/client/%s.pid", config.resource); pidfd = createPidFile(config.ident, pidpath, 0); if (pidfd == -1) { errMsg(LOG_ERR, "Could not create pid file %s, Exiting sync.", pidpath); return -1; } // if sync log does not exist, switch log snprintf(logpath, PATH_MAX, "%s/%s.sync", config.logdir, config.resource); errMsg(LOG_INFO, "logpath: %s", logpath); logfd = open(logpath, O_RDONLY); if (logfd == -1) { if (switchLog() != 0) { errMsg(LOG_ERR, "Could not switch log file. Stopping."); return -1; } logfd = open(logpath, O_RDONLY); if (logfd == -1) { errnoMsg(LOG_ERR, "Could not open log file %s", logpath); return -1; } newsync = 1; } // sync-id char id[SYNCID_MAX]; char idpath[PATH_MAX]; snprintf(idpath, PATH_MAX, "%s/%s.id", config.logdir, config.resource); // second part of the condition covers weird states after crash etc. if (newsync == 1 || readSyncId(id, idpath, SYNCID_MAX) != 0) { if (generateSyncId(id, SYNCID_MAX) != 0) { errMsg(LOG_ERR, "Could not get sync-id. Stopping."); return -1; } if (writeSyncId(id, idpath) != 0) { errMsg(LOG_ERR, "Could not write sync-id. Stopping."); return -1; } } // create snapshot if (newsync || !fileExists(config.snapshot)) { if (createSnapshot(config.rootdir, config.snapshot, 1) == -1) { errMsg(LOG_ERR, "Could not create snapshot of %s to %s Stopping.", config.rootdir, config.snapshot); return -1; } } // load log if (loadLog(logfd) != 0) { errMsg(LOG_ERR, "Could not load log %s", logpath); return -1; } // transfer changes if (transfer(config.host, config.port) == -1) { errMsg(LOG_ERR, "Error in transfer. Exiting sync."); // in case of failure only delete pid file if (deletePidFile(pidfd, pidpath) == -1) errExit(LOG_ERR, "Deleting PID file '%s'", pidpath); return -1; } // delete snapshot if (deleteSnapshot(config.snapshot) == -1) errMsg(LOG_ERR, "Could not delete snapshot %s", config.snapshot); // delete syncid if (unlink(idpath) == -1) errExit(LOG_ERR, "Deleting sync-id file '%s'", idpath); // delete sync log close(logfd); if (unlink(logpath) == -1) errExit(LOG_ERR, "Deleting log file '%s'", logpath); // delete pid file if (deletePidFile(pidfd, pidpath) == -1) errExit(LOG_ERR, "Deleting PID file '%s'", pidpath); return 0; }