Example #1
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;
}