Example #1
0
/*
 * 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;
  }
}
Example #2
0
/*
 * 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;
  }
}
Example #3
0
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());
}
Example #4
0
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);
}
Example #6
0
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;
}