VirtualBox

Changeset 38116 in vbox for trunk/src


Ignore:
Timestamp:
Jul 22, 2011 2:35:39 PM (14 years ago)
Author:
vboxsync
Message:

Main-CloneVM: split up the disks collecting for the different cloning modes;
MachineAndChildStates: find parent images which are not directly attached in
the cloned VM and merge them with the new children

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-server/MachineImplCloneVM.cpp

    r38061 r38116  
    2525#include <iprt/dir.h>
    2626#include <iprt/cpp/utils.h>
     27#ifdef DEBUG_poetzsch
     28# include <iprt/stream.h>
     29#endif
    2730
    2831#include <VBox/com/list.h>
     
    9497
    9598    /* Private helper methods */
     99
     100    /* MachineCloneVM::start helper: */
    96101    HRESULT createMachineList(const ComPtr<ISnapshot> &pSnapshot, RTCList< ComObjPtr<Machine> > &machineList) const;
     102    inline void updateProgressStats(MEDIUMTASKCHAIN &mtc, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight) const;
     103    inline HRESULT addSaveState(const ComObjPtr<Machine> &machine, ULONG &uCount, ULONG &uTotalWeight);
     104    inline HRESULT queryBaseName(const ComPtr<IMedium> &pMedium, Utf8Str &strBaseName) const;
     105    HRESULT queryMediasForMachineState(const RTCList<ComObjPtr<Machine> > &machineList, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight);
     106    HRESULT queryMediasForMachineAndChildStates(const RTCList<ComObjPtr<Machine> > &machineList, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight);
     107    HRESULT queryMediasForAllStates(const RTCList<ComObjPtr<Machine> > &machineList, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight);
     108
     109    /* MachineCloneVM::run helper: */
    97110    settings::Snapshot findSnapshot(settings::MachineConfigFile *pMCF, const settings::SnapshotsList &snl, const Guid &id) const;
    98111    void updateMACAddresses(settings::NetworkAdaptersList &nwl) const;
     
    137150    {
    138151        rc = createMachineList(sfaChilds[i], machineList);
     152        if (FAILED(rc)) return rc;
     153    }
     154
     155    return rc;
     156}
     157
     158void MachineCloneVMPrivate::updateProgressStats(MEDIUMTASKCHAIN &mtc, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight) const
     159{
     160    if (fAttachLinked)
     161    {
     162        /* Implicit diff creation as part of attach is a pretty cheap
     163         * operation, and does only need one operation per attachment. */
     164        ++uCount;
     165        uTotalWeight += 1;  /* 1MB per attachment */
     166    }
     167    else
     168    {
     169        /* Currently the copying of diff images involves reading at least
     170         * the biggest parent in the previous chain. So even if the new
     171         * diff image is small in size, it could need some time to create
     172         * it. Adding the biggest size in the chain should balance this a
     173         * little bit more, i.e. the weight is the sum of the data which
     174         * needs to be read and written. */
     175        uint64_t uMaxSize = 0;
     176        for (size_t e = mtc.chain.size(); e > 0; --e)
     177        {
     178            MEDIUMTASK &mt = mtc.chain.at(e - 1);
     179            mt.uWeight += uMaxSize;
     180
     181            /* Calculate progress data */
     182            ++uCount;
     183            uTotalWeight += mt.uWeight;
     184
     185            /* Save the max size for better weighting of diff image
     186             * creation. */
     187            uMaxSize = RT_MAX(uMaxSize, mt.uWeight);
     188        }
     189    }
     190}
     191
     192HRESULT MachineCloneVMPrivate::addSaveState(const ComObjPtr<Machine> &machine, ULONG &uCount, ULONG &uTotalWeight)
     193{
     194    Bstr bstrSrcSaveStatePath;
     195    HRESULT rc = machine->COMGETTER(StateFilePath)(bstrSrcSaveStatePath.asOutParam());
     196    if (FAILED(rc)) return rc;
     197    if (!bstrSrcSaveStatePath.isEmpty())
     198    {
     199        SAVESTATETASK sst;
     200        sst.snapshotUuid     = machine->getSnapshotId();
     201        sst.strSaveStateFile = bstrSrcSaveStatePath;
     202        uint64_t cbSize;
     203        int vrc = RTFileQuerySize(sst.strSaveStateFile.c_str(), &cbSize);
     204        if (RT_FAILURE(vrc))
     205            return p->setError(VBOX_E_IPRT_ERROR, p->tr("Could not query file size of '%s' (%Rrc)"), sst.strSaveStateFile.c_str(), vrc);
     206        /* same rule as above: count both the data which needs to
     207         * be read and written */
     208        sst.uWeight = 2 * (cbSize + _1M - 1) / _1M;
     209        llSaveStateFiles.append(sst);
     210        ++uCount;
     211        uTotalWeight += sst.uWeight;
     212    }
     213    return S_OK;
     214}
     215
     216HRESULT MachineCloneVMPrivate::queryBaseName(const ComPtr<IMedium> &pMedium, Utf8Str &strBaseName) const
     217{
     218    ComPtr<IMedium> pBaseMedium;
     219    HRESULT rc = pMedium->COMGETTER(Base)(pBaseMedium.asOutParam());
     220    if (FAILED(rc)) return rc;
     221    Bstr bstrBaseName;
     222    rc = pBaseMedium->COMGETTER(Name)(bstrBaseName.asOutParam());
     223    if (FAILED(rc)) return rc;
     224    strBaseName = bstrBaseName;
     225    return rc;
     226}
     227
     228HRESULT MachineCloneVMPrivate::queryMediasForMachineState(const RTCList<ComObjPtr<Machine> > &machineList, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight)
     229{
     230    /* This mode is pretty straightforward. We didn't need to know about any
     231     * parent/children relationship and therefor simply adding all directly
     232     * attached images of the source VM as cloning targets. The IMedium code
     233     * take than care to merge any (possibly) existing parents into the new
     234     * image. */
     235    HRESULT rc = S_OK;
     236    for (size_t i = 0; i < machineList.size(); ++i)
     237    {
     238        const ComObjPtr<Machine> &machine = machineList.at(i);
     239        /* If this is the Snapshot Machine we want to clone, we need to
     240         * create a new diff file for the new "current state". */
     241        const bool fCreateDiffs = (machine == pOldMachineState);
     242        /* Add all attachments of the different machines to a worker list. */
     243        SafeIfaceArray<IMediumAttachment> sfaAttachments;
     244        rc = machine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(sfaAttachments));
     245        if (FAILED(rc)) return rc;
     246        for (size_t a = 0; a < sfaAttachments.size(); ++a)
     247        {
     248            const ComPtr<IMediumAttachment> &pAtt = sfaAttachments[a];
     249            DeviceType_T type;
     250            rc = pAtt->COMGETTER(Type)(&type);
     251            if (FAILED(rc)) return rc;
     252
     253            /* Only harddisk's are of interest. */
     254            if (type != DeviceType_HardDisk)
     255                continue;
     256
     257            /* Valid medium attached? */
     258            ComPtr<IMedium> pSrcMedium;
     259            rc = pAtt->COMGETTER(Medium)(pSrcMedium.asOutParam());
     260            if (FAILED(rc)) return rc;
     261            if (pSrcMedium.isNull())
     262                continue;
     263
     264            /* Create the medium task chain. In this case it will always
     265             * contain one image only. */
     266            MEDIUMTASKCHAIN mtc;
     267            mtc.fCreateDiffs  = fCreateDiffs;
     268            mtc.fAttachLinked = fAttachLinked;
     269
     270            /* Refresh the state so that the file size get read. */
     271            MediumState_T e;
     272            rc = pSrcMedium->RefreshState(&e);
     273            if (FAILED(rc)) return rc;
     274            LONG64 lSize;
     275            rc = pSrcMedium->COMGETTER(Size)(&lSize);
     276            if (FAILED(rc)) return rc;
     277
     278            MEDIUMTASK mt;
     279
     280            /* Save the base name. */
     281            rc = queryBaseName(pSrcMedium, mt.strBaseName);
     282            if (FAILED(rc)) return rc;
     283
     284            /* Save the current medium, for later cloning. */
     285            mt.pMedium = pSrcMedium;
     286            if (fAttachLinked)
     287                mt.uWeight = 0; /* dummy */
     288            else
     289                mt.uWeight = (lSize + _1M - 1) / _1M;
     290            mtc.chain.append(mt);
     291
     292            /* Update the progress info. */
     293            updateProgressStats(mtc, fAttachLinked, uCount, uTotalWeight);
     294            /* Append the list of images which have  to be cloned. */
     295            llMedias.append(mtc);
     296        }
     297        /* Add the save state files of this machine if there is one. */
     298        rc = addSaveState(machine, uCount, uTotalWeight);
     299        if (FAILED(rc)) return rc;
     300    }
     301
     302    return rc;
     303}
     304
     305HRESULT MachineCloneVMPrivate::queryMediasForMachineAndChildStates(const RTCList<ComObjPtr<Machine> > &machineList, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight)
     306{
     307    /* This is basically a three step approach. First select all medias
     308     * directly or indirectly involved in the clone. Second create a histogram
     309     * of the usage of all that medias. Third select the medias which are
     310     * directly attached or have more than one directly/indirectly used child
     311     * in the new clone. Step one and two are done in the first loop.
     312     *
     313     * Example of the histogram counts after going through 3 attachments from
     314     * bottom to top:
     315     *
     316     *           3
     317     *           |
     318     *        -> 3
     319     *          / \
     320     *         2   1 <-
     321     *        /
     322     *    -> 2
     323     *      / \
     324     *  -> 1   1
     325     *          \
     326     *           1 <-
     327     *
     328     * Whenever the histogram count is changing compared to the previous one we
     329     * need to include that image in the cloning step (Marked with <-). If we
     330     * start at zero even the directly attached images are automatically
     331     * included.
     332     *
     333     * Note: This still leads to media chains which can have the same medium
     334     * included. This case is handled in "run" and therefor not critical, but
     335     * it leads to wrong progress infos which isn't nice. */
     336
     337    HRESULT rc = S_OK;
     338    std::map<ComPtr<IMedium>, uint32_t> mediaHist; /* Our usage histogram for the medias */
     339    for (size_t i = 0; i < machineList.size(); ++i)
     340    {
     341        const ComObjPtr<Machine> &machine = machineList.at(i);
     342        /* If this is the Snapshot Machine we want to clone, we need to
     343         * create a new diff file for the new "current state". */
     344        const bool fCreateDiffs = (machine == pOldMachineState);
     345        /* Add all attachments (and their parents) of the different
     346         * machines to a worker list. */
     347        SafeIfaceArray<IMediumAttachment> sfaAttachments;
     348        rc = machine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(sfaAttachments));
     349        if (FAILED(rc)) return rc;
     350        for (size_t a = 0; a < sfaAttachments.size(); ++a)
     351        {
     352            const ComPtr<IMediumAttachment> &pAtt = sfaAttachments[a];
     353            DeviceType_T type;
     354            rc = pAtt->COMGETTER(Type)(&type);
     355            if (FAILED(rc)) return rc;
     356
     357            /* Only harddisk's are of interest. */
     358            if (type != DeviceType_HardDisk)
     359                continue;
     360
     361            /* Valid medium attached? */
     362            ComPtr<IMedium> pSrcMedium;
     363            rc = pAtt->COMGETTER(Medium)(pSrcMedium.asOutParam());
     364            if (FAILED(rc)) return rc;
     365
     366            if (pSrcMedium.isNull())
     367                continue;
     368
     369            MEDIUMTASKCHAIN mtc;
     370            mtc.fCreateDiffs  = fCreateDiffs;
     371            mtc.fAttachLinked = fAttachLinked;
     372
     373            while (!pSrcMedium.isNull())
     374            {
     375                /* Build a histogram of used medias and the parent chain. */
     376                ++mediaHist[pSrcMedium];
     377
     378                /* Refresh the state so that the file size get read. */
     379                MediumState_T e;
     380                rc = pSrcMedium->RefreshState(&e);
     381                if (FAILED(rc)) return rc;
     382                LONG64 lSize;
     383                rc = pSrcMedium->COMGETTER(Size)(&lSize);
     384                if (FAILED(rc)) return rc;
     385
     386                MEDIUMTASK mt;
     387                mt.pMedium = pSrcMedium;
     388                mt.uWeight = (lSize + _1M - 1) / _1M;
     389                mtc.chain.append(mt);
     390
     391                /* Query next parent. */
     392                rc = pSrcMedium->COMGETTER(Parent)(pSrcMedium.asOutParam());
     393                if (FAILED(rc)) return rc;
     394            }
     395
     396            llMedias.append(mtc);
     397        }
     398        /* Add the save state files of this machine if there is one. */
     399        rc = addSaveState(machine, uCount, uTotalWeight);
     400        if (FAILED(rc)) return rc;
     401    }
     402#ifdef DEBUG_poetzsch
     403    /* Print the histogram */
     404    std::map<ComPtr<IMedium>, uint32_t>::iterator it;
     405    for (it = mediaHist.begin(); it != mediaHist.end(); ++it)
     406    {
     407        Bstr bstrSrcName;
     408        rc = (*it).first->COMGETTER(Name)(bstrSrcName.asOutParam());
     409        if (FAILED(rc)) return rc;
     410        RTPrintf("%ls: %d\n", bstrSrcName.raw(), (*it).second);
     411    }
     412#endif
     413    /* Go over every medium in the list and check if it either a directly
     414     * attached disk or has more than one children. If so it needs to be
     415     * replicated. Also we have to make sure that any direct or indirect
     416     * children knows of the new parent (which doesn't necessarily mean it
     417     * is a direct children in the source chain). */
     418    for (size_t i = 0; i < llMedias.size(); ++i)
     419    {
     420        MEDIUMTASKCHAIN &mtc = llMedias.at(i);
     421        RTCList<MEDIUMTASK> newChain;
     422        uint32_t used = 0;
     423        for (size_t a = 0; a < mtc.chain.size(); ++a)
     424        {
     425            const MEDIUMTASK &mt = mtc.chain.at(a);
     426            uint32_t hist = mediaHist[mt.pMedium];
     427#ifdef DEBUG_poetzsch
     428            Bstr bstrSrcName;
     429            rc = mt.pMedium->COMGETTER(Name)(bstrSrcName.asOutParam());
     430            if (FAILED(rc)) return rc;
     431            RTPrintf("%ls: %d (%d)\n", bstrSrcName.raw(), hist, used);
     432#endif
     433            /* Check if there is a "step" in the histogram when going the chain
     434             * upwards. If so, we need this image, cause there is another leave
     435             * from here in the cloned VM. */
     436            if (hist > used)
     437            {
     438                newChain.append(mt);
     439                used = hist;
     440            }
     441        }
     442        /* Make sure we always using the old base name as new base name, even
     443         * if the base is a differencing image in the source VM (with the UUID
     444         * as name). */
     445        rc = queryBaseName(newChain.last().pMedium, newChain.last().strBaseName);
     446        if (FAILED(rc)) return rc;
     447        /* Update the old medium chain with the updated one. */
     448        mtc.chain = newChain;
     449        /* Update the progress info. */
     450        updateProgressStats(mtc, fAttachLinked, uCount, uTotalWeight);
     451    }
     452
     453    return rc;
     454}
     455
     456HRESULT MachineCloneVMPrivate::queryMediasForAllStates(const RTCList<ComObjPtr<Machine> > &machineList, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight)
     457{
     458    /* In this case we create a exact copy of the original VM. This means just
     459     * adding all directly and indirectly attached disk images to the worker
     460     * list. */
     461    HRESULT rc = S_OK;
     462    for (size_t i = 0; i < machineList.size(); ++i)
     463    {
     464        const ComObjPtr<Machine> &machine = machineList.at(i);
     465        /* If this is the Snapshot Machine we want to clone, we need to
     466         * create a new diff file for the new "current state". */
     467        const bool fCreateDiffs = (machine == pOldMachineState);
     468        /* Add all attachments (and their parents) of the different
     469         * machines to a worker list. */
     470        SafeIfaceArray<IMediumAttachment> sfaAttachments;
     471        rc = machine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(sfaAttachments));
     472        if (FAILED(rc)) return rc;
     473        for (size_t a = 0; a < sfaAttachments.size(); ++a)
     474        {
     475            const ComPtr<IMediumAttachment> &pAtt = sfaAttachments[a];
     476            DeviceType_T type;
     477            rc = pAtt->COMGETTER(Type)(&type);
     478            if (FAILED(rc)) return rc;
     479
     480            /* Only harddisk's are of interest. */
     481            if (type != DeviceType_HardDisk)
     482                continue;
     483
     484            /* Valid medium attached? */
     485            ComPtr<IMedium> pSrcMedium;
     486            rc = pAtt->COMGETTER(Medium)(pSrcMedium.asOutParam());
     487            if (FAILED(rc)) return rc;
     488            if (pSrcMedium.isNull())
     489                continue;
     490
     491            /* Build up a child->parent list of this attachment. (Note: we are
     492             * not interested of any child's not attached to this VM. So this
     493             * will not create a full copy of the base/child relationship.) */
     494            MEDIUMTASKCHAIN mtc;
     495            mtc.fCreateDiffs  = fCreateDiffs;
     496            mtc.fAttachLinked = fAttachLinked;
     497
     498            while (!pSrcMedium.isNull())
     499            {
     500                /* Refresh the state so that the file size get read. */
     501                MediumState_T e;
     502                rc = pSrcMedium->RefreshState(&e);
     503                if (FAILED(rc)) return rc;
     504                LONG64 lSize;
     505                rc = pSrcMedium->COMGETTER(Size)(&lSize);
     506                if (FAILED(rc)) return rc;
     507
     508                /* Save the current medium, for later cloning. */
     509                MEDIUMTASK mt;
     510                mt.pMedium = pSrcMedium;
     511                mt.uWeight = (lSize + _1M - 1) / _1M;
     512                mtc.chain.append(mt);
     513
     514                /* Query next parent. */
     515                rc = pSrcMedium->COMGETTER(Parent)(pSrcMedium.asOutParam());
     516                if (FAILED(rc)) return rc;
     517            }
     518            /* Update the progress info. */
     519            updateProgressStats(mtc, fAttachLinked, uCount, uTotalWeight);
     520            /* Append the list of images which have  to be cloned. */
     521            llMedias.append(mtc);
     522        }
     523        /* Add the save state files of this machine if there is one. */
     524        rc = addSaveState(machine, uCount, uTotalWeight);
    139525        if (FAILED(rc)) return rc;
    140526    }
     
    328714                    }
    329715                    rc = pSnapshot->COMGETTER(Parent)(pSnapshot.asOutParam());
     716                    if (FAILED(rc)) throw rc;
    330717                }
    331718            }
     
    389776        }
    390777
    391         /* Go over every machine and walk over every attachment this machine has. */
     778        /* If we want to create a linked clone just attach the medium
     779         * associated with the snapshot. The rest is taken care of by
     780         * attach already, so no need to duplicate this. */
     781
     782        /* We have different approaches for getting the medias which needs to
     783         * be replicated based on the clone mode the user requested (this is
     784         * mostly about the full clone mode).
     785         * MachineState:
     786         * - Only the images which are directly attached to an source VM will
     787         *   be cloned. Any parent disks in the original chain will be merged
     788         *   into the final cloned disk.
     789         * MachineAndChildStates:
     790         * - In this case we search for images which have more than one
     791         *   children in the cloned VM or are directly attached to the new VM.
     792         *   All others will be merged into the remaining images which are
     793         *   cloned.
     794         *   This case is the most complicated one and needs several iterations
     795         *   to make sure we are only cloning images which are really
     796         *   necessary.
     797         * AllStates:
     798         * - All disks which are directly or indirectly attached to the
     799         *   original VM are cloned.
     800         *
     801         * Note: If you change something generic on one if the methods its
     802         * likely that it need changed in the others as well! */
    392803        ULONG uCount       = 2; /* One init task and the machine creation. */
    393804        ULONG uTotalWeight = 2; /* The init task and the machine creation is worth one. */
    394         for (size_t i = 0; i < machineList.size(); ++i)
    395         {
    396             ComObjPtr<Machine> machine = machineList.at(i);
    397             /* If this is the Snapshot Machine we want to clone, we need to
    398              * create a new diff file for the new "current state". */
    399             bool fCreateDiffs = false;
    400             if (machine == d->pOldMachineState)
    401                 fCreateDiffs = true;
    402             /* If we want to create a linked clone just attach the medium
    403              * associated with the snapshot. The rest is taken care of by
    404              * attach already, so no need to duplicate this. */
    405             bool fAttachLinked = false;
    406             if (d->options.contains(CloneOptions_Link))
    407                 fAttachLinked = true;
    408             SafeIfaceArray<IMediumAttachment> sfaAttachments;
    409             rc = machine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(sfaAttachments));
    410             if (FAILED(rc)) throw rc;
    411             /* Add all attachments (and their parents) of the different
    412              * machines to a worker list. */
    413             for (size_t a = 0; a < sfaAttachments.size(); ++a)
    414             {
    415                 const ComPtr<IMediumAttachment> &pAtt = sfaAttachments[a];
    416                 DeviceType_T type;
    417                 rc = pAtt->COMGETTER(Type)(&type);
    418                 if (FAILED(rc)) throw rc;
    419 
    420                 /* Only harddisk's are of interest. */
    421                 if (type != DeviceType_HardDisk)
    422                     continue;
    423 
    424                 /* Valid medium attached? */
    425                 ComPtr<IMedium> pSrcMedium;
    426                 rc = pAtt->COMGETTER(Medium)(pSrcMedium.asOutParam());
    427                 if (FAILED(rc)) throw rc;
    428                 if (pSrcMedium.isNull())
    429                     continue;
    430 
    431                 /* Build up a child->parent list of this attachment. (Note: we are
    432                  * not interested of any child's not attached to this VM. So this
    433                  * will not create a full copy of the base/child relationship.) */
    434                 MEDIUMTASKCHAIN mtc;
    435                 mtc.fCreateDiffs = fCreateDiffs;
    436                 mtc.fAttachLinked = fAttachLinked;
    437 
    438                 /* If the current state without any snapshots is cloned, we
    439                  * don't need any diff images in the new clone. Add the last
    440                  * medium to the list of medias to create only (the clone
    441                  * operation of IMedium will create a merged copy
    442                  * automatically). */
    443                 if (d->mode == CloneMode_MachineState)
    444                 {
    445                     /* Refresh the state so that the file size get read. */
    446                     MediumState_T e;
    447                     rc = pSrcMedium->RefreshState(&e);
    448                     if (FAILED(rc)) throw rc;
    449                     LONG64 lSize;
    450                     rc = pSrcMedium->COMGETTER(Size)(&lSize);
    451                     if (FAILED(rc)) throw rc;
    452 
    453                     ComPtr<IMedium> pBaseMedium;
    454                     rc = pSrcMedium->COMGETTER(Base)(pBaseMedium.asOutParam());
    455                     if (FAILED(rc)) throw rc;
    456 
    457                     MEDIUMTASK mt;
    458 
    459                     Bstr bstrBaseName;
    460                     rc = pBaseMedium->COMGETTER(Name)(bstrBaseName.asOutParam());
    461                     if (FAILED(rc)) throw rc;
    462 
    463                     /* Save the base name. */
    464                     mt.strBaseName = bstrBaseName;
    465 
    466                     /* Save the current medium, for later cloning. */
    467                     mt.pMedium = pSrcMedium;
    468                     if (fAttachLinked)
    469                         mt.uWeight = 0; /* dummy */
    470                     else
    471                         mt.uWeight = (lSize + _1M - 1) / _1M;
    472                     mtc.chain.append(mt);
    473                 }
    474                 else
    475                 {
    476                     /** @todo r=klaus this puts way too many images in the list
    477                      * when cloning a snapshot (sub)tree, which means that more
    478                      * images are cloned than necessary. It is just the easiest
    479                      * way to get a working VM, as getting the image
    480                      * parent/child relationships right for only the bare
    481                      * minimum cloning is rather tricky. */
    482                     while (!pSrcMedium.isNull())
    483                     {
    484                         /* Refresh the state so that the file size get read. */
    485                         MediumState_T e;
    486                         rc = pSrcMedium->RefreshState(&e);
    487                         if (FAILED(rc)) throw rc;
    488                         LONG64 lSize;
    489                         rc = pSrcMedium->COMGETTER(Size)(&lSize);
    490                         if (FAILED(rc)) throw rc;
    491 
    492                         /* Save the current medium, for later cloning. */
    493                         MEDIUMTASK mt;
    494                         mt.pMedium = pSrcMedium;
    495                         mt.uWeight = (lSize + _1M - 1) / _1M;
    496                         mtc.chain.append(mt);
    497 
    498                         /* Query next parent. */
    499                         rc = pSrcMedium->COMGETTER(Parent)(pSrcMedium.asOutParam());
    500                         if (FAILED(rc)) throw rc;
    501                     }
    502                 }
    503 
    504                 if (fAttachLinked)
    505                 {
    506                     /* Implicit diff creation as part of attach is a pretty cheap
    507                      * operation, and does only need one operation per attachment. */
    508                     ++uCount;
    509                     uTotalWeight += 1;  /* 1MB per attachment */
    510                 }
    511                 else
    512                 {
    513                     /* Currently the copying of diff images involves reading at least
    514                      * the biggest parent in the previous chain. So even if the new
    515                      * diff image is small in size, it could need some time to create
    516                      * it. Adding the biggest size in the chain should balance this a
    517                      * little bit more, i.e. the weight is the sum of the data which
    518                      * needs to be read and written. */
    519                     uint64_t uMaxSize = 0;
    520                     for (size_t e = mtc.chain.size(); e > 0; --e)
    521                     {
    522                         MEDIUMTASK &mt = mtc.chain.at(e - 1);
    523                         mt.uWeight += uMaxSize;
    524 
    525                         /* Calculate progress data */
    526                         ++uCount;
    527                         uTotalWeight += mt.uWeight;
    528 
    529                         /* Save the max size for better weighting of diff image
    530                          * creation. */
    531                         uMaxSize = RT_MAX(uMaxSize, mt.uWeight);
    532                     }
    533                 }
    534                 d->llMedias.append(mtc);
    535             }
    536             Bstr bstrSrcSaveStatePath;
    537             rc = machine->COMGETTER(StateFilePath)(bstrSrcSaveStatePath.asOutParam());
    538             if (FAILED(rc)) throw rc;
    539             if (!bstrSrcSaveStatePath.isEmpty())
    540             {
    541                 SAVESTATETASK sst;
    542                 sst.snapshotUuid     = machine->getSnapshotId();
    543                 sst.strSaveStateFile = bstrSrcSaveStatePath;
    544                 uint64_t cbSize;
    545                 int vrc = RTFileQuerySize(sst.strSaveStateFile.c_str(), &cbSize);
    546                 if (RT_FAILURE(vrc))
    547                     throw p->setError(VBOX_E_IPRT_ERROR, p->tr("Could not query file size of '%s' (%Rrc)"), sst.strSaveStateFile.c_str(), vrc);
    548                 /* same rule as above: count both the data which needs to
    549                  * be read and written */
    550                 sst.uWeight = 2 * (cbSize + _1M - 1) / _1M;
    551                 d->llSaveStateFiles.append(sst);
    552                 ++uCount;
    553                 uTotalWeight += sst.uWeight;
    554             }
    555         }
    556 
     805        bool fAttachLinked = d->options.contains(CloneOptions_Link); /* Linked clones requested? */
     806        switch (d->mode)
     807        {
     808            case CloneMode_MachineState:          d->queryMediasForMachineState(machineList, fAttachLinked, uCount, uTotalWeight); break;
     809            case CloneMode_MachineAndChildStates: d->queryMediasForMachineAndChildStates(machineList, fAttachLinked, uCount, uTotalWeight); break;
     810            case CloneMode_AllStates:             d->queryMediasForAllStates(machineList, fAttachLinked, uCount, uTotalWeight); break;
     811        }
     812
     813        /* Now create the progress project, so the user knows whats going on. */
    557814        rc = d->pProgress.createObject();
    558815        if (FAILED(rc)) throw rc;
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