VirtualBox

Changeset 23686 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
Oct 12, 2009 12:41:10 PM (15 years ago)
Author:
vboxsync
Message:

Main/LiveMigration: Added wrapper around the SSM stream so we can tell where it ends without knowing anything about its format. This gets rid of the temporary select-timeout-hack used for detecting a SSM stream close call. The new code only uses a select-timeout-hack for handling failures.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/ConsoleImpl-LiveMigration.cpp

    r23671 r23686  
    2020 */
    2121
     22
    2223/*******************************************************************************
    2324*   Header Files                                                               *
     
    4041
    4142
    42 
    4343/*******************************************************************************
    4444*   Structures and Typedefs                                                    *
     
    5555    PVM                 mpVM;
    5656    Utf8Str             mstrPassword;
     57    bool const          mfIsSource;
    5758
    5859    /** @name stream stuff
     
    6061    RTSOCKET            mhSocket;
    6162    uint64_t            moffStream;
     63    uint32_t            mcbReadBlock;
    6264    bool volatile       mfStopReading;
     65    bool volatile       mfEndOfStream;
     66    bool volatile       mfIOError;
    6367    /** @} */
    6468
    65     MigrationState(Console *pConsole, PVM pVM)
     69    MigrationState(Console *pConsole, PVM pVM, bool fIsSource)
    6670        : mptrConsole(pConsole)
    6771        , mpVM(pVM)
     72        , mfIsSource(fIsSource)
    6873        , mhSocket(NIL_RTSOCKET)
    6974        , moffStream(UINT64_MAX / 2)
     75        , mcbReadBlock(0)
    7076        , mfStopReading(false)
     77        , mfEndOfStream(false)
     78        , mfIOError(false)
    7179    {
    7280    }
     
    8593
    8694    MigrationStateSrc(Console *pConsole, PVM pVM)
    87         : MigrationState(pConsole, pVM)
     95        : MigrationState(pConsole, pVM, true /*fIsSource*/)
    8896        , muPort(UINT32_MAX)
    8997    {
     
    104112
    105113    MigrationStateDst(Console *pConsole, PVM pVM, IMachine *pMachine)
    106         : MigrationState(pConsole, pVM)
     114        : MigrationState(pConsole, pVM, false /*fIsSource*/)
    107115        , mpMachine(pMachine)
    108116        , mpvVMCallbackTask(NULL)
     
    113121};
    114122
     123
     124/**
     125 * TCP stream header.
     126 *
     127 * This is an extra layer for fixing the problem with figuring out when the SSM
     128 * stream ends.
     129 */
     130typedef struct MIGRATIONTCPHDR
     131{
     132    /** Magic value. */
     133    uint32_t    u32Magic;
     134    /** The size of the data block following this header.
     135     * 0 indicates the end of the stream. */
     136    uint32_t    cb;
     137} MIGRATIONTCPHDR;
     138/** Magic value for MIGRATIONTCPHDR::u32Magic. (Egberto Gismonti Amin) */
     139#define MIGRATIONTCPHDR_MAGIC       UINT32_C(0x19471205)
     140/** The max block size. */
     141#define MIGRATIONTCPHDR_MAX_SIZE    UINT32_C(0x00fffff8)
    115142
    116143
     
    207234    return S_OK;
    208235}
     236
    209237
    210238/**
     
    237265{
    238266    MigrationState *pState = (MigrationState *)pvUser;
    239     int rc = RTTcpWrite(pState->mhSocket, pvBuf, cbToWrite);
    240     if (RT_SUCCESS(rc))
    241     {
    242         pState->moffStream += cbToWrite;
    243         return VINF_SUCCESS;
    244     }
     267
     268    AssertReturn(cbToWrite > 0, VINF_SUCCESS);
     269    AssertReturn(pState->mfIsSource, VERR_INVALID_HANDLE);
     270
     271    for (;;)
     272    {
     273        /* Write block header. */
     274        MIGRATIONTCPHDR Hdr;
     275        Hdr.u32Magic = MIGRATIONTCPHDR_MAGIC;
     276        Hdr.cb       = RT_MIN(cbToWrite, MIGRATIONTCPHDR_MAX_SIZE);
     277        int rc = RTTcpWrite(pState->mhSocket, &Hdr, sizeof(Hdr));
     278        if (RT_FAILURE(rc))
     279        {
     280            LogRel(("Migration/TCP: Header write error: %Rrc\n", rc));
     281            return rc;
     282        }
     283
     284        /* Write the data. */
     285        rc = RTTcpWrite(pState->mhSocket, pvBuf, Hdr.cb);
     286        if (RT_FAILURE(rc))
     287        {
     288            LogRel(("Migration/TCP: Data write error: %Rrc (cb=%#x)\n", rc, Hdr.cb));
     289            return rc;
     290        }
     291        pState->moffStream += Hdr.cb;
     292        if (Hdr.cb == cbToWrite)
     293            return VINF_SUCCESS;
     294
     295        /* advance */
     296        cbToWrite -= Hdr.cb;
     297        pvBuf = (uint8_t const *)pvBuf + Hdr.cb;
     298    }
     299}
     300
     301
     302/**
     303 * Selects and poll for close condition.
     304 *
     305 * We can use a relatively high poll timeout here since it's only used to get
     306 * us out of error paths.  In the normal cause of events, we'll get a
     307 * end-of-stream header.
     308 *
     309 * @returns VBox status code.
     310 *
     311 * @param   pState          The migration state data.
     312 */
     313static int migrationTcpReadSelect(MigrationState *pState)
     314{
     315    int rc;
     316    do
     317    {
     318        rc = RTTcpSelectOne(pState->mhSocket, 1000);
     319        if (RT_FAILURE(rc) && rc != VERR_TIMEOUT)
     320        {
     321            pState->mfIOError = true;
     322            LogRel(("Migration/TCP: Header select error: %Rrc\n", rc));
     323            break;
     324        }
     325        if (pState->mfStopReading)
     326        {
     327            rc = VERR_EOF;
     328            break;
     329        }
     330    } while (rc == VERR_TIMEOUT);
    245331    return rc;
    246332}
     
    253339{
    254340    MigrationState *pState = (MigrationState *)pvUser;
     341    AssertReturn(!pState->mfIsSource, VERR_INVALID_HANDLE);
    255342
    256343    for (;;)
    257344    {
    258         int rc = RTTcpSelectOne(pState->mhSocket, 30); /** @todo fix this polling mess. */
    259         if (RT_SUCCESS(rc))
    260         {
    261             rc = RTTcpRead(pState->mhSocket, pvBuf, cbToRead, pcbRead);
     345        int rc;
     346
     347        /*
     348         * Check for various conditions and may have been signalled.
     349         */
     350        if (pState->mfEndOfStream)
     351            return VERR_EOF;
     352        if (pState->mfStopReading)
     353            return VERR_EOF;
     354        if (pState->mfIOError)
     355            return VERR_IO_GEN_FAILURE;
     356
     357        /*
     358         * If there is no more data in the current block, read the next
     359         * block header.
     360         */
     361        if (!pState->mcbReadBlock)
     362        {
     363            rc = migrationTcpReadSelect(pState);
    262364            if (RT_FAILURE(rc))
    263365                return rc;
    264             pState->moffStream += pcbRead ? *pcbRead : cbToRead;
     366            MIGRATIONTCPHDR Hdr;
     367            rc = RTTcpRead(pState->mhSocket, &Hdr, sizeof(Hdr), NULL);
     368            if (RT_FAILURE(rc))
     369            {
     370                pState->mfIOError = true;
     371                LogRel(("Migration/TCP: Header read error: %Rrc\n", rc));
     372                return rc;
     373            }
     374            if (   Hdr.u32Magic != MIGRATIONTCPHDR_MAGIC
     375                || Hdr.cb > MIGRATIONTCPHDR_MAX_SIZE)
     376            {
     377                pState->mfIOError = true;
     378                LogRel(("Migration/TCP: Invalid block: u32Magic=%#x cb=%#x\n", Hdr.u32Magic, Hdr.cb));
     379                return VERR_IO_GEN_FAILURE;
     380            }
     381
     382            pState->mcbReadBlock = Hdr.cb;
     383            if (!Hdr.cb)
     384            {
     385                pState->mfEndOfStream = true;
     386                return VERR_EOF;
     387            }
     388
     389            if (pState->mfStopReading)
     390                return VERR_EOF;
     391        }
     392
     393        /*
     394         * Read more data.
     395         */
     396        rc = migrationTcpReadSelect(pState);
     397        if (RT_FAILURE(rc))
     398            return rc;
     399        size_t cb = RT_MIN(pState->mcbReadBlock, cbToRead);
     400        rc = RTTcpRead(pState->mhSocket, pvBuf, cb, pcbRead);
     401        if (RT_FAILURE(rc))
     402        {
     403            pState->mfIOError = true;
     404            LogRel(("Migration/TCP: Data read error: %Rrc (cb=%#x)\n", rc, cb));
     405            return rc;
     406        }
     407        if (pcbRead)
     408        {
     409            pState->moffStream   += *pcbRead;
     410            pState->mcbReadBlock -= *pcbRead;
    265411            return VINF_SUCCESS;
    266412        }
    267         if (rc != VERR_TIMEOUT)
    268             return rc;
    269         if (pState->mfStopReading)
    270             return VERR_EOF;
     413        pState->moffStream   += cb;
     414        pState->mcbReadBlock -= cb;
     415        if (cbToRead == cb)
     416            return VINF_SUCCESS;
     417
     418        /* Advance to the next block. */
     419        cbToRead -= cb;
     420        pvBuf = (uint8_t *)pvBuf + cb;
    271421    }
    272422}
     
    307457{
    308458    MigrationState *pState = (MigrationState *)pvUser;
    309     ASMAtomicWriteBool(&pState->mfStopReading, true);
     459
     460    if (pState->mfIsSource)
     461    {
     462        MIGRATIONTCPHDR EofHdr = { MIGRATIONTCPHDR_MAGIC, 0 };
     463        int rc = RTTcpWrite(pState->mhSocket, &EofHdr, sizeof(EofHdr));
     464        if (RT_FAILURE(rc))
     465        {
     466            LogRel(("Migration/TCP: EOF Header write error: %Rrc\n", rc));
     467            return rc;
     468        }
     469    }
     470    else
     471    {
     472        ASMAtomicWriteBool(&pState->mfStopReading, true);
     473        RTTcpFlush(pState->mhSocket);
     474    }
     475
    310476    return VINF_SUCCESS;
    311477}
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