Example #1
0
static bool write_spool_header(DCR *dcr)
{
    spool_hdr hdr;
    ssize_t status;
    DEV_BLOCK *block = dcr->block;
    JCR *jcr = dcr->jcr;

    hdr.FirstIndex = block->FirstIndex;
    hdr.LastIndex = block->LastIndex;
    hdr.len = block->binbuf;

    /* Write header */
    for (int retry = 0; retry <= 1; retry++) {
        status = write(dcr->spool_fd, (char*)&hdr, sizeof(hdr));
        if (status == -1) {
            berrno be;

            Jmsg(jcr, M_FATAL, 0, _("Error writing header to spool file. ERR=%s\n"), be.bstrerror());
            jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
        }
        if (status != (ssize_t)sizeof(hdr)) {
            Jmsg(jcr, M_ERROR, 0, _("Error writing header to spool file."
                                    " Disk probably full. Attempting recovery. Wanted to write=%d got=%d\n"),
                 (int)status, (int)sizeof(hdr));
            /* If we wrote something, truncate it, then despool */
            if (status != -1) {
#if defined(HAVE_WIN32)
                boffset_t   pos = _lseeki64(dcr->spool_fd, (__int64)0, SEEK_CUR);
#else
                boffset_t   pos = lseek(dcr->spool_fd, 0, SEEK_CUR);
#endif
                if (ftruncate(dcr->spool_fd, pos - status) != 0) {
                    berrno be;

                    Jmsg(dcr->jcr, M_ERROR, 0, _("Ftruncate spool file failed: ERR=%s\n"), be.bstrerror());
                    /* Note, try continuing despite ftruncate problem */
                }
            }
            if (!despool_data(dcr, false)) {
                Jmsg(jcr, M_FATAL, 0, _("Fatal despooling error."));
                jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
                return false;
            }
            continue;                    /* try again */
        }
        return true;
    }
    Jmsg(jcr, M_FATAL, 0, _("Retrying after header spooling error failed.\n"));
    jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
    return false;
}
Example #2
0
/*
 * Read a block from the spool file
 *
 *  Returns RB_OK on success
 *          RB_EOT when file done
 *          RB_ERROR on error
 */
static int read_block_from_spool_file(DCR *dcr)
{
    uint32_t rlen;
    ssize_t status;
    spool_hdr hdr;
    DEV_BLOCK *block = dcr->block;
    JCR *jcr = dcr->jcr;

    rlen = sizeof(hdr);
    status = read(dcr->spool_fd, (char *)&hdr, (size_t)rlen);
    if (status == 0) {
        Dmsg0(100, "EOT on spool read.\n");
        return RB_EOT;
    } else if (status != (ssize_t)rlen) {
        if (status == -1) {
            berrno be;

            Jmsg(dcr->jcr, M_FATAL, 0, _("Spool header read error. ERR=%s\n"), be.bstrerror());
        } else {
            Pmsg2(000, _("Spool read error. Wanted %u bytes, got %d\n"), rlen, status);
            Jmsg2(jcr, M_FATAL, 0, _("Spool header read error. Wanted %u bytes, got %d\n"), rlen, status);
        }
        jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
        return RB_ERROR;
    }
    rlen = hdr.len;
    if (rlen > block->buf_len) {
        Pmsg2(000, _("Spool block too big. Max %u bytes, got %u\n"), block->buf_len, rlen);
        Jmsg2(jcr, M_FATAL, 0, _("Spool block too big. Max %u bytes, got %u\n"), block->buf_len, rlen);
        jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
        return RB_ERROR;
    }
    status = read(dcr->spool_fd, (char *)block->buf, (size_t)rlen);
    if (status != (ssize_t)rlen) {
        Pmsg2(000, _("Spool data read error. Wanted %u bytes, got %d\n"), rlen, status);
        Jmsg2(dcr->jcr, M_FATAL, 0, _("Spool data read error. Wanted %u bytes, got %d\n"), rlen, status);
        jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
        return RB_ERROR;
    }
    /* Setup write pointers */
    block->binbuf = rlen;
    block->bufp = block->buf + block->binbuf;
    block->FirstIndex = hdr.FirstIndex;
    block->LastIndex = hdr.LastIndex;
    block->VolSessionId = dcr->jcr->VolSessionId;
    block->VolSessionTime = dcr->jcr->VolSessionTime;
    Dmsg2(800, "Read block FI=%d LI=%d\n", block->FirstIndex, block->LastIndex);
    return RB_OK;
}
Example #3
0
static bool write_spool_data(DCR *dcr)
{
    ssize_t status;
    DEV_BLOCK *block = dcr->block;
    JCR *jcr = dcr->jcr;

    /* Write data */
    for (int retry = 0; retry <= 1; retry++) {
        status = write(dcr->spool_fd, block->buf, (size_t)block->binbuf);
        if (status == -1) {
            berrno be;

            Jmsg(jcr, M_FATAL, 0, _("Error writing data to spool file. ERR=%s\n"), be.bstrerror());
            jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
        }
        if (status != (ssize_t)block->binbuf) {
            /*
             * If we wrote something, truncate it and the header, then despool
             */
            if (status != -1) {
#if defined(HAVE_WIN32)
                boffset_t   pos = _lseeki64(dcr->spool_fd, (__int64)0, SEEK_CUR);
#else
                boffset_t   pos = lseek(dcr->spool_fd, 0, SEEK_CUR);
#endif
                if (ftruncate(dcr->spool_fd, pos - status - sizeof(spool_hdr)) != 0) {
                    berrno be;

                    Jmsg(dcr->jcr, M_ERROR, 0, _("Ftruncate spool file failed: ERR=%s\n"), be.bstrerror());
                    /* Note, try continuing despite ftruncate problem */
                }
            }
            if (!despool_data(dcr, false)) {
                Jmsg(jcr, M_FATAL, 0, _("Fatal despooling error."));
                jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
                return false;
            }
            if (!write_spool_header(dcr)) {
                return false;
            }
            continue;                    /* try again */
        }
        return true;
    }
    Jmsg(jcr, M_FATAL, 0, _("Retrying after data spooling error failed.\n"));
    jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
    return false;
}
Example #4
0
/*
 * NB! This routine locks the device, but if committing will
 *     not unlock it. If not committing, it will be unlocked.
 */
static bool despool_data(DCR *dcr, bool commit)
{
    DEVICE *rdev;
    DCR *rdcr;
    bool ok = true;
    DEV_BLOCK *block;
    JCR *jcr = dcr->jcr;
    int status;
    char ec1[50];
    BSOCK *dir = jcr->dir_bsock;

    Dmsg0(100, "Despooling data\n");
    if (jcr->dcr->job_spool_size == 0) {
        Jmsg(jcr, M_WARNING, 0, _("Despooling zero bytes. Your disk is probably FULL!\n"));
    }

    /*
     * Commit means that the job is done, so we commit, otherwise, we
     * are despooling because of user spool size max or some error
     * (e.g. filesystem full).
     */
    if (commit) {
        Jmsg(jcr, M_INFO, 0, _("Committing spooled data to Volume \"%s\". Despooling %s bytes ...\n"),
             jcr->dcr->VolumeName,
             edit_uint64_with_commas(jcr->dcr->job_spool_size, ec1));
        jcr->setJobStatus(JS_DataCommitting);
    } else {
        Jmsg(jcr, M_INFO, 0, _("Writing spooled data to Volume. Despooling %s bytes ...\n"),
             edit_uint64_with_commas(jcr->dcr->job_spool_size, ec1));
        jcr->setJobStatus(JS_DataDespooling);
    }
    jcr->sendJobStatus(JS_DataDespooling);
    dcr->despool_wait = true;
    dcr->spooling = false;
    /*
     * We work with device blocked, but not locked so that other threads
     * e.g. reservations can lock the device structure.
     */
    dcr->dblock(BST_DESPOOLING);
    dcr->despool_wait = false;
    dcr->despooling = true;

    /*
     * This is really quite kludgy and should be fixed some time.
     * We create a dev structure to read from the spool file
     * in rdev and rdcr.
     */
    rdev = (DEVICE *)malloc(sizeof(DEVICE));
    memset(rdev, 0, sizeof(DEVICE));
    rdev->dev_name = get_memory(strlen(spool_name)+1);
    bstrncpy(rdev->dev_name, spool_name, sizeof_pool_memory(rdev->dev_name));
    rdev->errmsg = get_pool_memory(PM_EMSG);
    *rdev->errmsg = 0;
    rdev->max_block_size = dcr->dev->max_block_size;
    rdev->min_block_size = dcr->dev->min_block_size;
    rdev->device = dcr->dev->device;
    rdcr = dcr->get_new_spooling_dcr();
    setup_new_dcr_device(jcr, rdcr, rdev, NULL);
    rdcr->spool_fd = dcr->spool_fd;
    block = dcr->block;                /* save block */
    dcr->block = rdcr->block;          /* make read and write block the same */

    Dmsg1(800, "read/write block size = %d\n", block->buf_len);
    lseek(rdcr->spool_fd, 0, SEEK_SET); /* rewind */

#if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
    posix_fadvise(rdcr->spool_fd, 0, 0, POSIX_FADV_WILLNEED);
#endif

    /* Add run time, to get current wait time */
    int32_t despool_start = time(NULL) - jcr->run_time;

    set_new_file_parameters(dcr);

    while (ok) {
        if (job_canceled(jcr)) {
            ok = false;
            break;
        }
        status = read_block_from_spool_file(rdcr);
        if (status == RB_EOT) {
            break;
        } else if (status == RB_ERROR) {
            ok = false;
            break;
        }
        ok = dcr->write_block_to_device();
        if (!ok) {
            Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
                  dcr->dev->print_name(), dcr->dev->bstrerror());
            Dmsg2(000, "Fatal append error on device %s: ERR=%s\n",
                  dcr->dev->print_name(), dcr->dev->bstrerror());
            /* Force in case Incomplete set */
            jcr->forceJobStatus(JS_FatalError);
        }
        Dmsg3(800, "Write block ok=%d FI=%d LI=%d\n", ok, block->FirstIndex, block->LastIndex);
    }

    /*
     * If this Job is incomplete, we need to backup the FileIndex
     *  to the last correctly saved file so that the JobMedia
     *  LastIndex is correct.
     */
    if (jcr->is_JobStatus(JS_Incomplete)) {
        dcr->VolLastIndex = dir->get_FileIndex();
        Dmsg1(100, "======= Set FI=%ld\n", dir->get_FileIndex());
    }

    if (!dcr->dir_create_jobmedia_record(false)) {
        Jmsg2(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
              dcr->getVolCatName(), jcr->Job);
        jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
    }
    /* Set new file/block parameters for current dcr */
    set_new_file_parameters(dcr);

    /*
     * Subtracting run_time give us elapsed time - wait_time since
     * we started despooling. Note, don't use time_t as it is 32 or 64
     * bits depending on the OS and doesn't edit with %d
     */
    int32_t despool_elapsed = time(NULL) - despool_start - jcr->run_time;

    if (despool_elapsed <= 0) {
        despool_elapsed = 1;
    }

    Jmsg(jcr, M_INFO, 0, _("Despooling elapsed time = %02d:%02d:%02d, Transfer rate = %s Bytes/second\n"),
         despool_elapsed / 3600, despool_elapsed % 3600 / 60, despool_elapsed % 60,
         edit_uint64_with_suffix(jcr->dcr->job_spool_size / despool_elapsed, ec1));

    dcr->block = block;                /* reset block */

    lseek(rdcr->spool_fd, 0, SEEK_SET); /* rewind */
    if (ftruncate(rdcr->spool_fd, 0) != 0) {
        berrno be;

        Jmsg(jcr, M_ERROR, 0, _("Ftruncate spool file failed: ERR=%s\n"), be.bstrerror());
        /* Note, try continuing despite ftruncate problem */
    }

    P(mutex);
    if (spool_stats.data_size < dcr->job_spool_size) {
        spool_stats.data_size = 0;
    } else {
        spool_stats.data_size -= dcr->job_spool_size;
    }
    V(mutex);
    P(dcr->dev->spool_mutex);
    dcr->dev->spool_size -= dcr->job_spool_size;
    dcr->job_spool_size = 0;            /* zap size in input dcr */
    V(dcr->dev->spool_mutex);
    free_memory(rdev->dev_name);
    free_pool_memory(rdev->errmsg);
    /* Be careful to NULL the jcr and free rdev after free_dcr() */
    rdcr->jcr = NULL;
    rdcr->set_dev(NULL);
    free_dcr(rdcr);
    free(rdev);
    dcr->spooling = true;           /* turn on spooling again */
    dcr->despooling = false;
    /*
     * Note, if committing we leave the device blocked. It will be removed in
     *  release_device();
     */
    if (!commit) {
        dcr->dev->dunblock();
    }
    jcr->sendJobStatus(JS_Running);
    return ok;
}