VirtualBox

Changeset 36074 in vbox


Ignore:
Timestamp:
Feb 24, 2011 3:38:25 PM (14 years ago)
Author:
vboxsync
Message:

Main: implement sharing saved state files between snapshots and machines in 'saved' state; this dramatically speeds up restoring snapshots as well as taking snapshots of 'saved' machines

Location:
trunk/src/VBox/Main
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/MachineImpl.h

    r36058 r36074  
    200200    struct SSData
    201201    {
    202         Utf8Str mStateFilePath;
     202        Utf8Str strStateFilePath;
    203203    };
    204204
     
    645645    Utf8Str queryLogFilename(ULONG idx);
    646646
     647    void composeSavedStateFilename(Utf8Str &strStateFilePath);
     648
    647649    HRESULT openRemoteSession(IInternalSessionControl *aControl,
    648650                              IN_BSTR aType, IN_BSTR aEnvironment,
     
    10071009    struct ConsoleTaskData
    10081010    {
    1009         ConsoleTaskData() : mLastState(MachineState_Null) {}
     1011        ConsoleTaskData()
     1012            : mLastState(MachineState_Null)
     1013        { }
    10101014
    10111015        MachineState_T mLastState;
     
    10161020
    10171021        // used when saving state (either as part of a snapshot or separate)
    1018         Utf8Str mStateFilePath;
     1022        Utf8Str strStateFilePath;
    10191023    };
    10201024
     
    10341038
    10351039    HRESULT endSavingState(HRESULT aRC, const Utf8Str &aErrMsg);
     1040    void releaseSavedStateFile(const Utf8Str &strSavedStateFile, Snapshot *pSnapshotToIgnore);
    10361041
    10371042    void deleteSnapshotHandler(DeleteSnapshotTask &aTask);
  • trunk/src/VBox/Main/include/SnapshotImpl.h

    r35638 r36074  
    9898    const ComObjPtr<Snapshot> getFirstChild() const;
    9999
    100     const Utf8Str& stateFilePath() const;
    101     HRESULT deleteStateFile();
     100    const Utf8Str& getStateFilePath() const;
    102101
    103102    ULONG getChildrenCount();
     
    119118                                   const Utf8Str &strNewPath);
    120119
     120    bool sharesSavedStateFile(const Utf8Str &strPath,
     121                              Snapshot *pSnapshotToIgnore);
     122
    121123    HRESULT saveSnapshot(settings::Snapshot &data, bool aAttrsOnly);
    122124    HRESULT saveSnapshotImpl(settings::Snapshot &data, bool aAttrsOnly);
  • trunk/src/VBox/Main/src-client/ConsoleImpl.cpp

    r36041 r36074  
    30763076    LogFlowFunc(("fTakingSnapshotOnline = %d, mMachineState = %d\n", fTakingSnapshotOnline, mMachineState));
    30773077
    3078     if (    fTakingSnapshotOnline
    3079          || mMachineState == MachineState_Saved
    3080        )
     3078    if (fTakingSnapshotOnline)
    30813079    {
    30823080        ++cOperations;
    3083 
    30843081        ulTotalOperationsWeight += ulMemSize;
    30853082    }
  • trunk/src/VBox/Main/src-server/MachineImpl.cpp

    r36072 r36074  
    23332333    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    23342334
    2335     mSSData->mStateFilePath.cloneTo(aStateFilePath);
     2335    mSSData->strStateFilePath.cloneTo(aStateFilePath);
    23362336
    23372337    return S_OK;
     
    43204320    {
    43214321        // add the saved state file to the list of files the caller should delete
    4322         Assert(!mSSData->mStateFilePath.isEmpty());
    4323         mData->llFilesToDelete.push_back(mSSData->mStateFilePath);
    4324 
    4325         mSSData->mStateFilePath.setNull();
     4322        Assert(!mSSData->strStateFilePath.isEmpty());
     4323        mData->llFilesToDelete.push_back(mSSData->strStateFilePath);
     4324
     4325        mSSData->strStateFilePath.setNull();
    43264326
    43274327        // unconditionally set the machine state to powered off, we now
     
    54275427    uint32_t u32Height = 0;
    54285428
    5429     int vrc = readSavedGuestSize(mSSData->mStateFilePath, uScreenId, &u32Width, &u32Height);
     5429    int vrc = readSavedGuestSize(mSSData->strStateFilePath, uScreenId, &u32Width, &u32Height);
    54305430    if (RT_FAILURE(vrc))
    54315431        return setError(VBOX_E_IPRT_ERROR,
     
    54605460    uint32_t u32Height = 0;
    54615461
    5462     int vrc = readSavedDisplayScreenshot(mSSData->mStateFilePath, 0 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
     5462    int vrc = readSavedDisplayScreenshot(mSSData->strStateFilePath, 0 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
    54635463
    54645464    if (RT_FAILURE(vrc))
     
    54975497    uint32_t u32Height = 0;
    54985498
    5499     int vrc = readSavedDisplayScreenshot(mSSData->mStateFilePath, 0 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
     5499    int vrc = readSavedDisplayScreenshot(mSSData->strStateFilePath, 0 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
    55005500
    55015501    if (RT_FAILURE(vrc))
     
    55605560    uint32_t u32Height = 0;
    55615561
    5562     int vrc = readSavedDisplayScreenshot(mSSData->mStateFilePath, 0 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
     5562    int vrc = readSavedDisplayScreenshot(mSSData->strStateFilePath, 0 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
    55635563
    55645564    if (RT_FAILURE(vrc))
     
    56095609    uint32_t u32Height = 0;
    56105610
    5611     int vrc = readSavedDisplayScreenshot(mSSData->mStateFilePath, 1 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
     5611    int vrc = readSavedDisplayScreenshot(mSSData->strStateFilePath, 1 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
    56125612
    56135613    if (RT_FAILURE(vrc))
     
    56465646    uint32_t u32Height = 0;
    56475647
    5648     int vrc = readSavedDisplayScreenshot(mSSData->mStateFilePath, 1 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
     5648    int vrc = readSavedDisplayScreenshot(mSSData->strStateFilePath, 1 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
    56495649
    56505650    if (RT_FAILURE(vrc))
     
    60866086                         logFolder.c_str(), RTPATH_DELIMITER, idx);
    60876087    return log;
     6088}
     6089
     6090/**
     6091 * Composes a unique saved state filename based on the current system time. The filename is
     6092 * granular to the second so this will work so long as no more than one snapshot is taken on
     6093 * a machine per second.
     6094 *
     6095 * Before version 4.1, we used this formula for saved state files:
     6096 *      Utf8StrFmt("%s%c{%RTuuid}.sav", strFullSnapshotFolder.c_str(), RTPATH_DELIMITER, mData->mUuid.raw())
     6097 * which no longer works because saved state files can now be shared between the saved state of the
     6098 * "saved" machine and an online snapshot, and the following would cause problems:
     6099 * 1) save machine
     6100 * 2) create online snapshot from that machine state --> reusing saved state file
     6101 * 3) save machine again --> filename would be reused, breaking the online snapshot
     6102 *
     6103 * So instead we now use a timestamp.
     6104 *
     6105 * @param str
     6106 */
     6107void Machine::composeSavedStateFilename(Utf8Str &strStateFilePath)
     6108{
     6109    AutoCaller autoCaller(this);
     6110    AssertComRCReturnVoid(autoCaller.rc());
     6111
     6112    {
     6113        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     6114        calculateFullPath(mUserData->s.strSnapshotFolder, strStateFilePath);
     6115    }
     6116
     6117    RTTIMESPEC ts;
     6118    RTTimeNow(&ts);
     6119    RTTIME time;
     6120    RTTimeExplode(&time, &ts);
     6121
     6122    strStateFilePath += RTPATH_DELIMITER;
     6123    strStateFilePath += Utf8StrFmt("%04ld-%02hd-%02hdT%02hd:%02hd:%02hdZ.sav",
     6124                                   time.i32Year,
     6125                                   (uint16_t)time.u8Month,
     6126                                   (uint16_t)time.u8MonthDay,
     6127                                   (uint16_t)time.u8Hour,
     6128                                   (uint16_t)time.u8Minute,
     6129                                   (uint16_t)time.u8Second);
    60886130}
    60896131
     
    71157157    // stateFile (optional)
    71167158    if (config.strStateFile.isEmpty())
    7117         mSSData->mStateFilePath.setNull();
     7159        mSSData->strStateFilePath.setNull();
    71187160    else
    71197161    {
     
    71257167                            config.strStateFile.c_str(),
    71267168                            vrc);
    7127         mSSData->mStateFilePath = stateFilePathFull;
     7169        mSSData->strStateFilePath = stateFilePathFull;
    71287170    }
    71297171
     
    71917233    if (config.fAborted)
    71927234    {
    7193         Assert(!mSSData->mStateFilePath.isEmpty());
    7194         mSSData->mStateFilePath.setNull();
     7235        Assert(!mSSData->strStateFilePath.isEmpty());
     7236        mSSData->strStateFilePath.setNull();
    71957237
    71967238        /* no need to use setMachineState() during init() */
    71977239        mData->mMachineState = MachineState_Aborted;
    71987240    }
    7199     else if (!mSSData->mStateFilePath.isEmpty())
     7241    else if (!mSSData->strStateFilePath.isEmpty())
    72007242    {
    72017243        /* no need to use setMachineState() during init() */
     
    80548096            }
    80558097
    8056             /* update the saved state file path */
    8057             Utf8Str path = mSSData->mStateFilePath;
    8058             if (RTPathStartsWith(path.c_str(), configDir.c_str()))
    8059                 mSSData->mStateFilePath = Utf8StrFmt("%s%s",
    8060                                                      newConfigDir.c_str(),
    8061                                                      path.c_str() + configDir.length());
    8062 
    8063             /* Update saved state file paths of all online snapshots.
    8064              * Note that saveSettings() will recognize name change
    8065              * and will save all snapshots in this case. */
     8098            // in the saved state file path, replace the old directory with the new directory
     8099            if (RTPathStartsWith(mSSData->strStateFilePath.c_str(), configDir.c_str()))
     8100                mSSData->strStateFilePath = newConfigDir.append(mSSData->strStateFilePath.c_str() + configDir.length());
     8101
     8102            // and do the same thing for the saved state file paths of all the online snapshots
    80668103            if (mData->mFirstSnapshot)
    80678104                mData->mFirstSnapshot->updateSavedStatePaths(configDir.c_str(),
     
    82968333                  || mData->mMachineState == MachineState_DeletingSnapshotOnline
    82978334                  || mData->mMachineState == MachineState_DeletingSnapshotPaused)
    8298               && (!mSSData->mStateFilePath.isEmpty())
     8335              && (!mSSData->strStateFilePath.isEmpty())
    82998336            )
    83008337        )
    83018338    {
    8302         Assert(!mSSData->mStateFilePath.isEmpty());
     8339        Assert(!mSSData->strStateFilePath.isEmpty());
    83038340        /* try to make the file name relative to the settings file dir */
    8304         copyPathRelativeToMachine(mSSData->mStateFilePath, config.strStateFile);
     8341        copyPathRelativeToMachine(mSSData->strStateFilePath, config.strStateFile);
    83058342    }
    83068343    else
    83078344    {
    8308         Assert(mSSData->mStateFilePath.isEmpty() || mData->mMachineState == MachineState_Saving);
     8345        Assert(mSSData->strStateFilePath.isEmpty() || mData->mMachineState == MachineState_Saving);
    83098346        config.strStateFile.setNull();
    83108347    }
     
    84038440            Automatically upgrade from 1 to 2 when there is no saved state. (ugly!) */
    84048441        if (    mHWData->mHWVersion == "1"
    8405              && mSSData->mStateFilePath.isEmpty()
     8442             && mSSData->strStateFilePath.isEmpty()
    84068443           )
    84078444            mHWData->mHWVersion = "2";  /** @todo Is this safe, to update mHWVersion here? If not some other point needs to be found where this can be done. */
     
    87558792        if (aFlags & SaveSTS_StateFilePath)
    87568793        {
    8757             if (!mSSData->mStateFilePath.isEmpty())
     8794            if (!mSSData->strStateFilePath.isEmpty())
    87588795                /* try to make the file name relative to the settings file dir */
    8759                 copyPathRelativeToMachine(mSSData->mStateFilePath, mData->pMachineConfigFile->strStateFile);
     8796                copyPathRelativeToMachine(mSSData->strStateFilePath, mData->pMachineConfigFile->strStateFile);
    87608797            else
    87618798                mData->pMachineConfigFile->strStateFile.setNull();
     
    87658802        {
    87668803            Assert(    mData->mMachineState != MachineState_Aborted
    8767                     || mSSData->mStateFilePath.isEmpty());
     8804                    || mSSData->strStateFilePath.isEmpty());
    87688805
    87698806            mData->pMachineConfigFile->timeLastStateChange = mData->mLastStateChange;
     
    95549591 *
    95559592 * @note Locks this object for writing!
     9593 *
     9594 * @todo r=dj this needs a pllRegistriesThatNeedSaving as well
    95569595 */
    95579596void Machine::rollbackMedia()
     
    1042910468    }
    1043010469
    10431     Assert(mConsoleTaskData.mStateFilePath.isEmpty() || !mConsoleTaskData.mSnapshot);
    10432     if (!mConsoleTaskData.mStateFilePath.isEmpty())
     10470    Assert(    mConsoleTaskData.strStateFilePath.isEmpty()
     10471            || !mConsoleTaskData.mSnapshot);
     10472    if (!mConsoleTaskData.strStateFilePath.isEmpty())
    1043310473    {
    1043410474        LogWarningThisFunc(("canceling failed save state request!\n"));
     
    1044210482         * their parents back by rolling back mMediaData) */
    1044310483        rollbackMedia();
    10444         /* delete the saved state file (it might have been already created) */
    10445         if (mConsoleTaskData.mSnapshot->stateFilePath().length())
    10446             RTFileDelete(mConsoleTaskData.mSnapshot->stateFilePath().c_str());
    10447 
     10484
     10485        // delete the saved state file (it might have been already created)
     10486        // AFTER killing the snapshot so that releaseSavedStateFile() won't
     10487        // think it's still in use
     10488        Utf8Str strStateFile = mConsoleTaskData.mSnapshot->getStateFilePath();
    1044810489        mConsoleTaskData.mSnapshot->uninit();
     10490        releaseSavedStateFile(strStateFile, NULL /* pSnapshotToIgnore */ );
    1044910491    }
    1045010492
     
    1102711069    AssertReturn(    mData->mMachineState == MachineState_Paused
    1102811070                  && mConsoleTaskData.mLastState == MachineState_Null
    11029                   && mConsoleTaskData.mStateFilePath.isEmpty(),
     11071                  && mConsoleTaskData.strStateFilePath.isEmpty(),
    1103011072                 E_FAIL);
    1103111073
     
    1103811080                    FALSE /* aCancelable */);
    1103911081
    11040     Bstr stateFilePath;
     11082    Utf8Str strStateFilePath;
    1104111083    /* stateFilePath is null when the machine is not running */
    1104211084    if (mData->mMachineState == MachineState_Paused)
    11043     {
    11044         Utf8Str strFullSnapshotFolder;
    11045         calculateFullPath(mUserData->s.strSnapshotFolder, strFullSnapshotFolder);
    11046         stateFilePath = Utf8StrFmt("%s%c{%RTuuid}.sav",
    11047                                    strFullSnapshotFolder.c_str(),
    11048                                    RTPATH_DELIMITER,
    11049                                    mData->mUuid.raw());
    11050     }
     11085        composeSavedStateFilename(strStateFilePath);
    1105111086
    1105211087    /* fill in the console task data */
    1105311088    mConsoleTaskData.mLastState = mData->mMachineState;
    11054     mConsoleTaskData.mStateFilePath = stateFilePath;
     11089    mConsoleTaskData.strStateFilePath = strStateFilePath;
    1105511090    mConsoleTaskData.mProgress = pProgress;
    1105611091
     
    1105811093    setMachineState(MachineState_Saving);
    1105911094
    11060     stateFilePath.cloneTo(aStateFilePath);
     11095    strStateFilePath.cloneTo(aStateFilePath);
    1106111096    pProgress.queryInterfaceTo(aProgress);
    1106211097
     
    1108011115                      || (FAILED(iResult) && mData->mMachineState == MachineState_Saving))
    1108111116                  && mConsoleTaskData.mLastState != MachineState_Null
    11082                   && !mConsoleTaskData.mStateFilePath.isEmpty(),
     11117                  && !mConsoleTaskData.strStateFilePath.isEmpty(),
    1108311118                 E_FAIL);
    1108411119
     
    1112211157                        vrc);
    1112311158
    11124     mSSData->mStateFilePath = stateFilePathFull;
     11159    mSSData->strStateFilePath = stateFilePathFull;
    1112511160
    1112611161    /* The below setMachineState() will detect the state transition and will
     
    1179111826    if (SUCCEEDED(aRc))
    1179211827    {
    11793         mSSData->mStateFilePath = mConsoleTaskData.mStateFilePath;
     11828        mSSData->strStateFilePath = mConsoleTaskData.strStateFilePath;
    1179411829
    1179511830        /* save all VM settings */
     
    1180011835    else
    1180111836    {
    11802         /* delete the saved state file (it might have been already created) */
    11803         RTFileDelete(mConsoleTaskData.mStateFilePath.c_str());
     11837        // delete the saved state file (it might have been already created);
     11838        // we need not check whether this is shared with a snapshot here because
     11839        // we certainly created this saved state file here anew
     11840        RTFileDelete(mConsoleTaskData.strStateFilePath.c_str());
    1180411841    }
    1180511842
     
    1182111858    /* clear out the temporary saved state data */
    1182211859    mConsoleTaskData.mLastState = MachineState_Null;
    11823     mConsoleTaskData.mStateFilePath.setNull();
     11860    mConsoleTaskData.strStateFilePath.setNull();
    1182411861    mConsoleTaskData.mProgress.setNull();
    1182511862
    1182611863    LogFlowThisFuncLeave();
    1182711864    return rc;
     11865}
     11866
     11867/**
     11868 * Deletes the given file if it is no longer in use by either the current machine state
     11869 * (if the machine is "saved") or any of the machine's snapshots.
     11870 *
     11871 * Note: This checks mSSData->strStateFilePath, which is shared by the Machine and SessionMachine
     11872 * but is different for each SnapshotMachine. When calling this, the order of calling this
     11873 * function on the one hand and changing that variable OR the snapshots tree on the other hand
     11874 * is therefore critical. I know, it's all rather messy.
     11875 *
     11876 * @param strStateFile
     11877 * @param pSnapshotToIgnore  Passed to Snapshot::sharesSavedStateFile(); this snapshot is ignored in the test for whether the saved state file is in use.
     11878 */
     11879void SessionMachine::releaseSavedStateFile(const Utf8Str &strStateFile,
     11880                                           Snapshot *pSnapshotToIgnore)
     11881{
     11882    // it is safe to delete this saved state file if it is not currently in use by the machine ...
     11883    if (    (strStateFile.isNotEmpty())
     11884         && (strStateFile != mSSData->strStateFilePath)     // session machine's saved state
     11885       )
     11886        // ... and it must also not be shared with other snapshots
     11887        if (    !mData->mFirstSnapshot
     11888             || !mData->mFirstSnapshot->sharesSavedStateFile(strStateFile, pSnapshotToIgnore)
     11889                                // this checks the SnapshotMachine's state file paths
     11890           )
     11891            RTFileDelete(strStateFile.c_str());
    1182811892}
    1182911893
     
    1207912143        if (mRemoveSavedState)
    1208012144        {
    12081             Assert(!mSSData->mStateFilePath.isEmpty());
    12082             RTFileDelete(mSSData->mStateFilePath.c_str());
    12083         }
    12084         mSSData->mStateFilePath.setNull();
     12145            Assert(!mSSData->strStateFilePath.isEmpty());
     12146
     12147            // it is safe to delete the saved state file if ...
     12148            if (    !mData->mFirstSnapshot      // ... we have no snapshots or
     12149                 || !mData->mFirstSnapshot->sharesSavedStateFile(mSSData->strStateFilePath, NULL /* pSnapshotToIgnore */)
     12150                                                // ... none of the snapshots share the saved state file
     12151               )
     12152                RTFileDelete(mSSData->strStateFilePath.c_str());
     12153        }
     12154
     12155        mSSData->strStateFilePath.setNull();
    1208512156        stsFlags |= SaveSTS_StateFilePath;
    1208612157    }
     
    1210612177    {
    1210712178        /* the saved state file was adopted */
    12108         Assert(!mSSData->mStateFilePath.isEmpty());
     12179        Assert(!mSSData->strStateFilePath.isEmpty());
    1210912180        stsFlags |= SaveSTS_StateFilePath;
    1211012181    }
  • trunk/src/VBox/Main/src-server/SnapshotImpl.cpp

    r35984 r36074  
    428428    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    429429
    430     *aOnline = !stateFilePath().isEmpty();
     430    *aOnline = getStateFilePath().isNotEmpty();
    431431    return S_OK;
    432432}
     
    504504 *      Must be called from under the object's lock!
    505505 */
    506 const Utf8Str& Snapshot::stateFilePath() const
    507 {
    508     return m->pMachine->mSSData->mStateFilePath;
    509 }
    510 
    511 /**
    512  *  @note
    513  *      Must be called from under the object's write lock!
    514  */
    515 HRESULT Snapshot::deleteStateFile()
    516 {
    517     int vrc = RTFileDelete(m->pMachine->mSSData->mStateFilePath.c_str());
    518     if (RT_SUCCESS(vrc))
    519         m->pMachine->mSSData->mStateFilePath.setNull();
    520     return RT_SUCCESS(vrc) ? S_OK : E_FAIL;
     506const Utf8Str& Snapshot::getStateFilePath() const
     507{
     508    return m->pMachine->mSSData->strStateFilePath;
    521509}
    522510
     
    688676    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    689677
    690     const Utf8Str &path = m->pMachine->mSSData->mStateFilePath;
     678    const Utf8Str &path = m->pMachine->mSSData->strStateFilePath;
    691679    LogFlowThisFunc(("Snap[%s].statePath={%s}\n", m->strName.c_str(), path.c_str()));
    692680
     
    696684       )
    697685    {
    698         m->pMachine->mSSData->mStateFilePath = Utf8StrFmt("%s%s",
    699                                                           strNewPath.c_str(),
    700                                                           path.c_str() + strOldPath.length());
     686        m->pMachine->mSSData->strStateFilePath = Utf8StrFmt("%s%s",
     687                                                            strNewPath.c_str(),
     688                                                            path.c_str() + strOldPath.length());
    701689        LogFlowThisFunc(("-> updated: {%s}\n", path.c_str()));
    702690    }
     
    710698    }
    711699}
     700
     701/**
     702 * Returns true if this snapshot or one of its children uses the given file,
     703 * whose path must be fully qualified, as its saved state. When invoked on a
     704 * machine's first snapshot, this can be used to check if a saved state file
     705 * is shared with any snapshots.
     706 *
     707 * Caller must hold the machine lock, which protects the snapshots tree.
     708 *
     709 * @param strPath
     710 * @param pSnapshotToIgnore If != NULL, this snapshot is ignored during the checks.
     711 * @return
     712 */
     713bool Snapshot::sharesSavedStateFile(const Utf8Str &strPath,
     714                                    Snapshot *pSnapshotToIgnore)
     715{
     716    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     717    const Utf8Str &path = m->pMachine->mSSData->strStateFilePath;
     718
     719    if (!pSnapshotToIgnore || pSnapshotToIgnore != this)
     720        if (path.isNotEmpty())
     721            if (path == strPath)
     722                return true;        // no need to recurse then
     723
     724    // but otherwise we must check children
     725    for (SnapshotsList::const_iterator it = m->llChildren.begin();
     726         it != m->llChildren.end();
     727         ++it)
     728    {
     729        Snapshot *pChild = *it;
     730        if (!pSnapshotToIgnore || pSnapshotToIgnore != pChild)
     731            if (pChild->sharesSavedStateFile(strPath, pSnapshotToIgnore))
     732                return true;
     733    }
     734
     735    return false;
     736}
     737
    712738
    713739/**
     
    757783        return S_OK;
    758784
    759     /* stateFile (optional) */
    760     if (!stateFilePath().isEmpty())
    761         m->pMachine->copyPathRelativeToMachine(stateFilePath(), data.strStateFile);
     785    // state file (only if this snapshot is online)
     786    if (getStateFilePath().isNotEmpty())
     787        m->pMachine->copyPathRelativeToMachine(getStateFilePath(), data.strStateFile);
    762788    else
    763789        data.strStateFile.setNull();
     
    870896        return rc;
    871897
    872     // now report the saved state file
    873     if (!m->pMachine->mSSData->mStateFilePath.isEmpty())
    874         llFilenames.push_back(m->pMachine->mSSData->mStateFilePath);
     898    // report the saved state file if it's not on the list yet
     899    if (!m->pMachine->mSSData->strStateFilePath.isEmpty())
     900    {
     901        bool fFound = false;
     902        for (std::list<Utf8Str>::const_iterator it = llFilenames.begin();
     903             it != llFilenames.end();
     904             ++it)
     905        {
     906            const Utf8Str &str = *it;
     907            if (str == m->pMachine->mSSData->strStateFilePath)
     908            {
     909                fFound = true;
     910                break;
     911            }
     912        }
     913        if (!fFound)
     914            llFilenames.push_back(m->pMachine->mSSData->strStateFilePath);
     915    }
    875916
    876917    this->beginSnapshotDelete();
     
    952993    /* SSData is always unique for SnapshotMachine */
    953994    mSSData.allocate();
    954     mSSData->mStateFilePath = aStateFilePath;
     995    mSSData->strStateFilePath = aStateFilePath;
    955996
    956997    HRESULT rc = S_OK;
     
    10901131    /* SSData is always unique for SnapshotMachine */
    10911132    mSSData.allocate();
    1092     mSSData->mStateFilePath = aStateFilePath;
     1133    mSSData->strStateFilePath = aStateFilePath;
    10931134
    10941135    /* create all other child objects that will be immutable private copies */
     
    12621303    RestoreSnapshotTask(SessionMachine *m,
    12631304                        Progress *p,
    1264                         Snapshot *s,
    1265                         ULONG ulStateFileSizeMB)
    1266         : SnapshotTask(m, p, s),
    1267           m_ulStateFileSizeMB(ulStateFileSizeMB)
     1305                        Snapshot *s)
     1306        : SnapshotTask(m, p, s)
    12681307    {}
    12691308
     
    12721311        pMachine->restoreSnapshotHandler(*this);
    12731312    }
    1274 
    1275     ULONG       m_ulStateFileSizeMB;
    12761313};
    12771314
     
    13991436    Utf8Str strStateFilePath;
    14001437    /* stateFilePath is null when the machine is not online nor saved */
    1401     if (    fTakingSnapshotOnline
    1402          || mData->mMachineState == MachineState_Saved)
    1403     {
    1404         Utf8Str strFullSnapshotFolder;
    1405         calculateFullPath(mUserData->s.strSnapshotFolder, strFullSnapshotFolder);
    1406         strStateFilePath = Utf8StrFmt("%s%c{%RTuuid}.sav",
    1407                                       strFullSnapshotFolder.c_str(),
    1408                                       RTPATH_DELIMITER,
    1409                                       snapshotId.raw());
    1410         /* ensure the directory for the saved state file exists */
     1438    if (fTakingSnapshotOnline)
     1439        // creating a new online snapshot: then we need a fresh saved state file
     1440        composeSavedStateFilename(strStateFilePath);
     1441    else if (mData->mMachineState == MachineState_Saved)
     1442        // taking an online snapshot from machine in "saved" state: then use existing state file
     1443        strStateFilePath = mSSData->strStateFilePath;
     1444
     1445    if (strStateFilePath.isNotEmpty())
     1446    {
     1447        // ensure the directory for the saved state file exists
    14111448        HRESULT rc = VirtualBox::ensureFilePathExists(strStateFilePath);
    14121449        if (FAILED(rc)) return rc;
     
    14641501            throw rc;
    14651502
    1466         if (mConsoleTaskData.mLastState == MachineState_Saved)
    1467         {
    1468             Utf8Str stateFrom = mSSData->mStateFilePath;
    1469             Utf8Str stateTo = mConsoleTaskData.mSnapshot->stateFilePath();
    1470 
    1471             LogFlowThisFunc(("Copying the execution state from '%s' to '%s'...\n",
    1472                              stateFrom.c_str(), stateTo.c_str()));
    1473 
    1474             aConsoleProgress->SetNextOperation(Bstr(tr("Copying the execution state")).raw(),
    1475                                                1);        // weight
    1476 
    1477             /* Leave the lock before a lengthy operation (machine is protected
    1478              * by "Saving" machine state now) */
    1479             alock.release();
    1480 
    1481             /* copy the state file */
    1482             int vrc = RTFileCopyEx(stateFrom.c_str(),
    1483                                    stateTo.c_str(),
    1484                                    0,
    1485                                    progressCallback,
    1486                                    aConsoleProgress);
    1487             alock.acquire();
    1488 
    1489             if (RT_FAILURE(vrc))
    1490                 /** @todo r=bird: Delete stateTo when appropriate. */
    1491                 throw setError(E_FAIL,
    1492                                tr("Could not copy the state file '%s' to '%s' (%Rrc)"),
    1493                                stateFrom.c_str(),
    1494                                stateTo.c_str(),
    1495                                vrc);
    1496         }
    1497 
    14981503        // if we got this far without an error, then save the media registries
    14991504        // that got modified for the diff images
     
    15961601
    15971602        rc = saveSettings(NULL, flSaveSettings);
    1598                 // no need to change for whether VirtualBox.xml needs saving since
    1599                 // we'll save the global settings below anyway
    16001603    }
    16011604
     
    16181621        mData->mCurrentSnapshot = pOldCurrentSnap;      // might have been changed above
    16191622
    1620         /* delete the saved state file (it might have been already created) */
    1621         if (mConsoleTaskData.mSnapshot->stateFilePath().length())
    1622             RTFileDelete(mConsoleTaskData.mSnapshot->stateFilePath().c_str());
     1623        // delete the saved state file (it might have been already created)
     1624        if (fOnline)
     1625            // no need to test for whether the saved state file is shared: an online
     1626            // snapshot means that a new saved state file was created, which we must
     1627            // clean up now
     1628            RTFileDelete(mConsoleTaskData.mSnapshot->getStateFilePath().c_str());
    16231629
    16241630        mConsoleTaskData.mSnapshot->uninit();
     
    16281634    mConsoleTaskData.mLastState = MachineState_Null;
    16291635    mConsoleTaskData.mSnapshot.setNull();
    1630 
    1631     // save VirtualBox.xml (media registry most probably changed with diff image);
    1632     // for that we should hold only the VirtualBox lock
    1633     machineLock.release();
    1634     AutoWriteLock vboxLock(mParent COMMA_LOCKVAL_SRC_POS);
    1635     mParent->saveSettings();
    16361636
    16371637    return rc;
     
    17081708    }
    17091709
    1710     ULONG ulStateFileSizeMB = 0;
    1711     if (pSnapshot->stateFilePath().length())
    1712     {
    1713         ++ulOpCount;      // one for the saved state
    1714 
    1715         uint64_t ullSize;
    1716         int irc = RTFileQuerySize(pSnapshot->stateFilePath().c_str(), &ullSize);
    1717         if (!RT_SUCCESS(irc))
    1718             // if we can't access the file here, then we'll be doomed later also, so fail right away
    1719             setError(E_FAIL, tr("Cannot access state file '%s', runtime error, %Rra"), pSnapshot->stateFilePath().c_str(), irc);
    1720         if (ullSize == 0) // avoid division by zero
    1721             ullSize = _1M;
    1722 
    1723         ulStateFileSizeMB = (ULONG)(ullSize / _1M);
    1724         LogFlowThisFunc(("op %d: saved state file '%s' has %RI64 bytes (%d MB)\n",
    1725                          ulOpCount, pSnapshot->stateFilePath().c_str(), ullSize, ulStateFileSizeMB));
    1726 
    1727         ulTotalWeight += ulStateFileSizeMB;
    1728     }
    1729 
    17301710    ComObjPtr<Progress> pProgress;
    17311711    pProgress.createObject();
     
    17421722    RestoreSnapshotTask *task = new RestoreSnapshotTask(this,
    17431723                                                        pProgress,
    1744                                                         pSnapshot,
    1745                                                         ulStateFileSizeMB);
     1724                                                        pSnapshot);
    17461725    int vrc = RTThreadCreate(NULL,
    17471726                             taskHandler,
     
    18221801        if (aTask.machineStateBackup == MachineState_Saved)
    18231802        {
    1824             Assert(!mSSData->mStateFilePath.isEmpty());
    1825             RTFileDelete(mSSData->mStateFilePath.c_str());
    1826             mSSData->mStateFilePath.setNull();
     1803            Assert(!mSSData->strStateFilePath.isEmpty());
     1804
     1805            // release the saved state file AFTER unsetting the member variable
     1806            // so that releaseSavedStateFile() won't think it's still in use
     1807            Utf8Str strStateFile(mSSData->strStateFilePath);
     1808            mSSData->strStateFilePath.setNull();
     1809            releaseSavedStateFile(strStateFile, NULL /* pSnapshotToIgnore */ );
     1810
    18271811            aTask.modifyBackedUpState(MachineState_PoweredOff);
     1812
    18281813            rc = saveStateSettings(SaveSTS_StateFilePath);
    18291814            if (FAILED(rc))
     
    18721857
    18731858            /* should not have a saved state file associated at this point */
    1874             Assert(mSSData->mStateFilePath.isEmpty());
    1875 
    1876             if (!aTask.pSnapshot->stateFilePath().isEmpty())
    1877             {
    1878                 Utf8Str snapStateFilePath = aTask.pSnapshot->stateFilePath();
    1879 
    1880                 Utf8Str strFullSnapshotFolder;
    1881                 calculateFullPath(mUserData->s.strSnapshotFolder, strFullSnapshotFolder);
    1882                 Utf8Str stateFilePath = Utf8StrFmt("%s%c{%RTuuid}.sav",
    1883                                                    strFullSnapshotFolder.c_str(),
    1884                                                    RTPATH_DELIMITER,
    1885                                                    mData->mUuid.raw());
    1886 
    1887                 LogFlowThisFunc(("Copying saved state file from '%s' to '%s'...\n",
    1888                                   snapStateFilePath.c_str(), stateFilePath.c_str()));
    1889 
    1890                 aTask.pProgress->SetNextOperation(Bstr(tr("Restoring the execution state")).raw(),
    1891                                                   aTask.m_ulStateFileSizeMB);        // weight
    1892 
    1893                 /* leave the lock before the potentially lengthy operation */
    1894                 snapshotLock.release();
    1895                 alock.leave();
    1896 
    1897                 /* copy the state file */
    1898                 RTFileDelete(stateFilePath.c_str());
    1899                 int vrc = RTFileCopyEx(snapStateFilePath.c_str(),
    1900                                        stateFilePath.c_str(),
    1901                                        0,
    1902                                        progressCallback,
    1903                                        static_cast<IProgress*>(aTask.pProgress));
    1904 
    1905                 alock.enter();
    1906                 snapshotLock.acquire();
    1907 
    1908                 if (RT_SUCCESS(vrc))
    1909                     mSSData->mStateFilePath = stateFilePath;
    1910                 else
    1911                     throw setError(E_FAIL,
    1912                                    tr("Could not copy the state file '%s' to '%s' (%Rrc)"),
    1913                                    snapStateFilePath.c_str(),
    1914                                    stateFilePath.c_str(),
    1915                                    vrc);
    1916             }
     1859            Assert(mSSData->strStateFilePath.isEmpty());
     1860
     1861            const Utf8Str &strSnapshotStateFile = aTask.pSnapshot->getStateFilePath();
     1862
     1863            if (strSnapshotStateFile.isNotEmpty())
     1864                // online snapshot: then share the state file
     1865                mSSData->strStateFilePath = strSnapshotStateFile;
    19171866
    19181867            LogFlowThisFunc(("Setting new current snapshot {%RTuuid}\n", aTask.pSnapshot->getId().raw()));
     
    19501899        /* we have already deleted the current state, so set the execution
    19511900         * state accordingly no matter of the delete snapshot result */
    1952         if (!mSSData->mStateFilePath.isEmpty())
     1901        if (mSSData->strStateFilePath.isNotEmpty())
    19531902            setMachineState(MachineState_Saved);
    19541903        else
     
    21442093    ULONG ulTotalWeight = 1;        // one for preparations
    21452094
    2146     if (pSnapshot->stateFilePath().length())
     2095    if (pSnapshot->getStateFilePath().length())
    21472096    {
    21482097        ++ulOpCount;
     
    25292478            AutoWriteLock machineLock(this COMMA_LOCKVAL_SRC_POS);
    25302479
    2531             Utf8Str stateFilePath = aTask.pSnapshot->stateFilePath();
     2480            Utf8Str stateFilePath = aTask.pSnapshot->getStateFilePath();
    25322481            if (!stateFilePath.isEmpty())
    25332482            {
     
    25352484                                                  1);        // weight
    25362485
    2537                 aTask.pSnapshot->deleteStateFile();
    2538                 // machine needs saving now
     2486                releaseSavedStateFile(stateFilePath, aTask.pSnapshot /* pSnapshotToIgnore */);
     2487
     2488                // machine will need saving now
    25392489                mParent->addGuidToListUniquely(llRegistriesThatNeedSaving, getId());
    25402490            }
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette