Esempio n. 1
0
int main(int argc, char **argv)
{
    int chunk_size = 10;
    int n_chunks = 10;
    int bufsize= n_chunks * chunk_size;
    char base_data[bufsize+1];
    char buffer[bufsize+1];
    char log1_data[bufsize+1];
    char log2_data[bufsize+1];
    char log3_data[bufsize+1];
    tbuffer_t tbuf;
    ex_iovec_t ex_iov, ex_iov_table[n_chunks];
    int i, err;
    char *fname = NULL;
    exnode_t *ex;
    exnode_exchange_t *exp;
    segment_t *seg, *clone, *clone2, *clone3;
    seglog_priv_t *s;
    opque_t *q;

    if (argc < 2) {
        printf("\n");
        printf("log_test LIO_COMMON_OPTIONS log.ex3\n");
        lio_print_options(stdout);
        printf("    log.ex3 - Log file to use.  IF the file is not empty all it's contents are truncated\n");
        printf("\n");
        return(1);
    }

    lio_init(&argc, &argv);

    //*** Parse the args
    //** This is the remote file to download
    i = 1;
    fname = argv[i];
    i++;
    if (fname == NULL) {
        printf("Missing log file!\n");
        return(2);
    }

    //** Load it
    exp = exnode_exchange_load_file(fname);

    //** and parse the remote exnode
    ex = exnode_create();
    if (exnode_deserialize(ex, exp, lio_gc->ess) != 0) {
        printf("ERROR parsing exnode!  Aborting!\n");
        abort();
    }

    //** Get the default view to use
    seg = exnode_get_default(ex);
    if (seg == NULL) {
        printf("No default segment!  Aborting!\n");
        abort();
    }
    s = (seglog_priv_t *)seg->priv;

    //** Verify the type
    if (strcmp(segment_type(seg), SEGMENT_TYPE_LOG) != 0) {
        printf("Invalid exnode type.  Segment should be a single level log but got a type of %s\n", segment_type(seg));
        abort();
    }

    //** Now get the base type.  It should NOT be a log
    if (strcmp(segment_type(s->base_seg), SEGMENT_TYPE_LOG) == 0) {
        printf("Log segments base should NOT be another log segment!\n");
        abort();
    }


    //** Truncate the log and base
    q = new_opque();
    opque_add(q, segment_truncate(s->table_seg, lio_gc->da, 0, lio_gc->timeout));
    opque_add(q, segment_truncate(s->data_seg, lio_gc->da, 0, lio_gc->timeout));
    opque_add(q, segment_truncate(s->base_seg, lio_gc->da, 0, lio_gc->timeout));
    err = opque_waitall(q);
    if (err != OP_STATE_SUCCESS) {
        printf("Error with truncate of initial log segment!\n");
        abort();
    }
    s->file_size = 0;
    s->data_size = 0;
    s->log_size = 0;

    //*************************************************************************
    //--------------------- Testing starts here -------------------------------
    //*************************************************************************

    //*************************************************************************
    //------- Generate a base with an empty log and read back -----------------
    //*************************************************************************
    //** Make the base buffer and write it
    memset(base_data, 'B', bufsize);
    base_data[bufsize] = '\0';
    tbuffer_single(&tbuf, bufsize, base_data);
    ex_iovec_single(&ex_iov, 0, bufsize);
    { int result = gop_sync_exec(segment_write(s->base_seg, lio_gc->da, NULL, 1, &ex_iov, &tbuf, 0, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }

    s->file_size = bufsize;  //** Since we're peeking we have to adjust the file size
    tbuffer_single(&tbuf, bufsize, buffer);  //** Read it directly back fro mthe base to make sure that works
    { int result = gop_sync_exec(segment_read(s->base_seg, lio_gc->da, NULL, 1, &ex_iov, &tbuf, 0, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    buffer[bufsize] = '\0';
    { int result = strcmp(buffer, base_data); assert(result == 0); }

    //** Do the same for the log
    { int result = gop_sync_exec(segment_read(seg, lio_gc->da, NULL, 1, &ex_iov, &tbuf, 0, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    { int result = compare_buffers_print(buffer, base_data, bufsize, 0); assert(result == 0); }

    //*************************************************************************
    //-- Clone the base structure and the use segment_copy to copy the data and verify --
    //*************************************************************************
    clone = NULL;
    { int result = gop_sync_exec(segment_clone(seg, lio_gc->da, &clone, CLONE_STRUCTURE, NULL, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    { int result = gop_sync_exec(segment_copy(lio_gc->tpc_unlimited, lio_gc->da, NULL, seg, clone, 0, 0, bufsize, chunk_size, buffer, 0, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    memset(buffer, 0, bufsize);
    { int result = gop_sync_exec(segment_read(clone, lio_gc->da, NULL, 1, &ex_iov, &tbuf, 0, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    { int result = compare_buffers_print(buffer, base_data, bufsize, 0); assert(result == 0); }

    //*************************************************************************
    //-------------------- Write to the log and read back ---------------------
    //*************************************************************************
    //** We are writing 1's to the even chunks
    memcpy(log1_data, base_data, bufsize);
    memset(buffer, '1', chunk_size);
    for (i=0; i<n_chunks; i+=2) {
        memcpy(&(log1_data[i*chunk_size]), buffer, chunk_size);
        ex_iovec_single(&(ex_iov_table[i]), i*chunk_size, chunk_size);
        opque_add(q, segment_write(seg, lio_gc->da, NULL, 1, &(ex_iov_table[i]), &tbuf, 0, lio_gc->timeout));
    }
    { int result = opque_waitall(q); assert(result == OP_STATE_SUCCESS); }

    //** Read it back
    memset(buffer, 0, bufsize);
    { int result = gop_sync_exec(segment_read(seg, lio_gc->da, NULL, 1, &ex_iov, &tbuf, 0, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    { int result = compare_buffers_print(buffer, log1_data, bufsize, 0); assert(result == 0); }

    //*************************************************************************
    //------------------- Merge_with base and verify --------------------------
    //*************************************************************************
    { int result = gop_sync_exec(slog_merge_with_base(seg, lio_gc->da, chunk_size, buffer, 1, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }

    //** Read it back
    memset(buffer, 0, bufsize);
    { int result = gop_sync_exec(segment_read(seg, lio_gc->da, NULL, 1, &ex_iov, &tbuf, 0, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    { int result = compare_buffers_print(buffer, log1_data, bufsize, 0); assert(result == 0); }

    //*************************************************************************
    //--------------- Write to the new empty log and verify -------------------
    //*************************************************************************
    //** We are writing 2's to *most* of the odd chunks
    memcpy(log1_data, buffer, bufsize);
    memset(buffer, '2', chunk_size);
    for (i=1; i<n_chunks; i+=2) {
        memcpy(&(log1_data[i*chunk_size]), buffer, chunk_size);
        ex_iovec_single(&(ex_iov_table[i]), i*chunk_size, chunk_size);
        opque_add(q, segment_write(seg, lio_gc->da, NULL, 1, &(ex_iov_table[i]), &tbuf, 0, lio_gc->timeout));
    }
    { int result = opque_waitall(q); assert(result == OP_STATE_SUCCESS); }

    //** Read it back
    memset(buffer, 0, bufsize);
    { int result = gop_sync_exec(segment_read(seg, lio_gc->da, NULL, 1, &ex_iov, &tbuf, 0, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    { int result = compare_buffers_print(buffer, log1_data, bufsize, 0); assert(result == 0); }

    //*************************************************************************
    //---------- Replace the clones base with seg(Log1) and verify ------------
    //*************************************************************************
    { int result = gop_sync_exec(segment_remove(clone, lio_gc->da, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    segment_destroy(clone);
    clone = NULL;
    { int result = gop_sync_exec(segment_clone(seg, lio_gc->da, &clone, CLONE_STRUCTURE, NULL, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }

    s = (seglog_priv_t *)clone->priv;

    s->base_seg = seg;
    s->file_size = segment_size(seg);

    //** Read it back
    memset(buffer, 0, bufsize);
    { int result = gop_sync_exec(segment_read(clone, lio_gc->da, NULL, 1, &ex_iov, &tbuf, 0, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    { int result = compare_buffers_print(buffer, log1_data, bufsize, 0); assert(result == 0); }

    //*************************************************************************
    //---------- Write to the clones log and verify (now have 2 logs) ---------
    //*************************************************************************
    memcpy(log2_data, log1_data, bufsize);
    memset(buffer, '3', 1.5*chunk_size);
    for (i=0; i<n_chunks; i+=4) {
        memcpy(&(log2_data[i*chunk_size]), buffer, 1.5*chunk_size);
        ex_iovec_single(&(ex_iov_table[i]), i*chunk_size, 1.5*chunk_size);
        opque_add(q, segment_write(clone, lio_gc->da, NULL, 1, &(ex_iov_table[i]), &tbuf, 0, lio_gc->timeout));
    }
    { int result = opque_waitall(q); assert(result == OP_STATE_SUCCESS); }

    //** Read it back
    memset(buffer, 0, bufsize);
    { int result = gop_sync_exec(segment_read(clone, lio_gc->da, NULL, 1, &ex_iov, &tbuf, 0, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    { int result = compare_buffers_print(buffer, log2_data, bufsize, 0); assert(result == 0); }

    //*************************************************************************
    //---- clone2 = clone (structure and data). Verify the contents -----------
    //*************************************************************************
    clone2 = NULL;
    { int result = gop_sync_exec(segment_clone(clone, lio_gc->da, &clone2, CLONE_STRUCT_AND_DATA, NULL, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    memset(buffer, 0, bufsize);
    { int result = gop_sync_exec(segment_read(clone2, lio_gc->da, NULL, 1, &ex_iov, &tbuf, 0, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    { int result = compare_buffers_print(buffer, log2_data, bufsize, 0); assert(result == 0); }

    //** We don't need this anymore so destroy it
    { int result = gop_sync_exec(segment_remove(clone2, lio_gc->da, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    segment_destroy(clone2);

    //*************************************************************************
    //---------------- Clone2 = clone's structure *only* ----------------------
    //*************************************************************************
    clone2 = NULL;
    { int result = gop_sync_exec(segment_clone(clone, lio_gc->da, &clone2, CLONE_STRUCTURE, NULL, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }

    //*************************************************************************
    //-------------- Replace clone2's base with clone and verify --------------
    //*************************************************************************
    s = (seglog_priv_t *)clone2->priv;
    { int result = gop_sync_exec(segment_remove(s->base_seg, lio_gc->da, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    segment_destroy(s->base_seg);

    s->base_seg = clone;
    s->file_size = segment_size(clone);

    //** Read it back
    memset(buffer, 0, bufsize);
    { int result = gop_sync_exec(segment_read(clone2, lio_gc->da, NULL, 1, &ex_iov, &tbuf, 0, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    { int result = compare_buffers_print(buffer, log2_data, bufsize, 0); assert(result == 0); }

    //*************************************************************************
    //----------- Write to Clone2 and verify (now have 3 logs) ----------------
    //*************************************************************************
    memcpy(log3_data, log2_data, bufsize);
    memset(buffer, '4', chunk_size);
    for (i=0; i<n_chunks; i+=2) {
        memcpy(&(log3_data[i*chunk_size + chunk_size/3]), buffer, chunk_size);
        ex_iovec_single(&(ex_iov_table[i]), i*chunk_size + chunk_size/3, chunk_size);
        opque_add(q, segment_write(clone2, lio_gc->da, NULL, 1, &(ex_iov_table[i]), &tbuf, 0, lio_gc->timeout));
    }
    { int result = opque_waitall(q); assert(result == OP_STATE_SUCCESS); }

    //** Read it back
    memset(buffer, 0, bufsize);
    { int result = gop_sync_exec(segment_read(clone2, lio_gc->da, NULL, 1, &ex_iov, &tbuf, 0, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    { int result = compare_buffers_print(buffer, log3_data, bufsize, 0); assert(result == 0); }

    //*************************************************************************
    // -- clone3 = clone2 structure and contents and verify
    //*************************************************************************
    clone3 = NULL;
    { int result = gop_sync_exec(segment_clone(clone2, lio_gc->da, &clone3, CLONE_STRUCT_AND_DATA, NULL, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    memset(buffer, 0, bufsize);
    { int result = gop_sync_exec(segment_read(clone3, lio_gc->da, NULL, 1, &ex_iov, &tbuf, 0, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    { int result = compare_buffers_print(buffer, log3_data, bufsize, 0); assert(result == 0); }

    //*************************************************************************
    //--------------------- Testing Finished -------------------------------
    //*************************************************************************

    //** Clean up
    { int result = gop_sync_exec(segment_remove(clone3, lio_gc->da, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }
    { int result = gop_sync_exec(segment_remove(clone2, lio_gc->da, lio_gc->timeout)); assert(result == OP_STATE_SUCCESS); }

    segment_destroy(clone3);
    segment_destroy(clone2);
    segment_destroy(seg);


    exnode_exchange_destroy(exp);

    lio_shutdown();

    return(0);
}
Esempio n. 2
0
op_status_t segment_put_func(void *arg, int id)
{
    segment_copy_t *sc = (segment_copy_t *)arg;
    tbuffer_t *wbuf, *rbuf, *tmpbuf;
    tbuffer_t tbuf1, tbuf2;
    char *rb, *wb, *tb;
    ex_off_t bufsize;
    int err;
    ex_off_t rpos, wpos, rlen, wlen, tlen, nbytes, got, dend;
    ex_iovec_t wex;
    op_generic_t *gop;
    op_status_t status;
    apr_time_t loop_start, file_start;
    double dt_loop, dt_file;

    //** Set up the buffers
    bufsize = sc->bufsize / 2;  //** The buffer is split for R/W
    rb = sc->buffer;
    wb = &(sc->buffer[bufsize]);
    tbuffer_single(&tbuf1, bufsize, rb);
    tbuffer_single(&tbuf2, bufsize, wb);
    rbuf = &tbuf1;
    wbuf = &tbuf2;

    nbytes = sc->len;
    status = op_success_status;

    //** Go ahead and reserve the space in the destintaion
    dend = sc->dest_offset + nbytes;
    gop_sync_exec(segment_truncate(sc->dest, sc->da, -dend, sc->timeout));

    //** Read the initial block
    rpos = 0;
    wpos = sc->dest_offset;
    if (nbytes < 0) {
        rlen = bufsize;
    } else {
        rlen = (nbytes > bufsize) ? bufsize : nbytes;
    }

    wlen = 0;
    rpos += rlen;
    nbytes -= rlen;
    log_printf(0, "FILE fd=%p bufsize=" XOT " rlen=" XOT " nbytes=" XOT "\n", sc->fd, bufsize, rlen, nbytes);

    loop_start = apr_time_now();
    got = fread(rb, 1, rlen, sc->fd);
    dt_file = apr_time_now() - loop_start;
    dt_file /= (double)APR_USEC_PER_SEC;

    if (got == 0) {
        if (feof(sc->fd) == 0)  {
            log_printf(1, "ERROR from fread=%d  dest sid=" XIDT " rlen=" XOT " got=" XOT "\n", errno, segment_id(sc->dest), rlen, got);
            status = op_failure_status;
        }
        goto finished;
    }
    rlen = got;

    do {
        //** Swap the buffers
        tb = rb;
        rb = wb;
        wb = tb;
        tmpbuf = rbuf;
        rbuf = wbuf;
        wbuf = tmpbuf;
        tlen = rlen;
        rlen = wlen;
        wlen = tlen;

        log_printf(1, "dseg=" XIDT " wpos=" XOT " rlen=" XOT " wlen=" XOT "\n", segment_id(sc->dest), wpos, rlen, wlen);

        //** Start the write
        ex_iovec_single(&wex, wpos, wlen);
        wpos += wlen;
        loop_start = apr_time_now();
        gop = segment_write(sc->dest, sc->da, sc->rw_hints, 1, &wex, wbuf, 0, sc->timeout);
        gop_start_execution(gop);  //** Start doing the transfer

        //** Read in the next block
        if (nbytes < 0) {
            rlen = bufsize;
        } else {
            rlen = (nbytes > bufsize) ? bufsize : nbytes;
        }
        if (rlen > 0) {
            file_start = apr_time_now();
            got = fread(rb, 1, rlen, sc->fd);
            dt_file = apr_time_now() - file_start;
            dt_file /= (double)APR_USEC_PER_SEC;
            if (got == 0) {
                if (feof(sc->fd) == 0)  {
                    log_printf(1, "ERROR from fread=%d  dest sid=" XIDT " got=" XOT " rlen=" XOT "\n", errno, segment_id(sc->dest), got, rlen);
                    status = op_failure_status;
                    gop_waitall(gop);
                    gop_free(gop, OP_DESTROY);
                    goto finished;
                }
            }
            rlen = got;
            rpos += rlen;
            nbytes -= rlen;
        }

        //** Wait for it to complete
        err = gop_waitall(gop);
        dt_loop = apr_time_now() - loop_start;
        dt_loop /= (double)APR_USEC_PER_SEC;

        log_printf(1, "dt_loop=%lf  dt_file=%lf\n", dt_loop, dt_file);

        if (err != OP_STATE_SUCCESS) {
            log_printf(1, "ERROR write(dseg=" XIDT ") failed! wpos=" XOT " len=" XOT "\n", segment_id(sc->dest), wpos, wlen);
            status = op_failure_status;
            gop_free(gop, OP_DESTROY);
            goto finished;
        }
        gop_free(gop, OP_DESTROY);
    } while (rlen > 0);

    if (sc->truncate == 1) {  //** Truncate if wanted
        gop_sync_exec(segment_truncate(sc->dest, sc->da, wpos, sc->timeout));
    }

finished:
//  status.error_code = rpos;

    return(status);
}
Esempio n. 3
0
op_status_t segment_copy_func(void *arg, int id)
{
    segment_copy_t *sc = (segment_copy_t *)arg;
    tbuffer_t *wbuf, *rbuf, *tmpbuf;
    tbuffer_t tbuf1, tbuf2;
    int err;
    ex_off_t bufsize;
    ex_off_t rpos, wpos, rlen, wlen, tlen, nbytes, dend;
    ex_iovec_t rex, wex;
    opque_t *q;
    op_generic_t *rgop, *wgop;
    op_status_t status;

    //** Set up the buffers
    bufsize = sc->bufsize / 2;  //** The buffer is split for R/W
    tbuffer_single(&tbuf1, bufsize, sc->buffer);
    tbuffer_single(&tbuf2, bufsize, &(sc->buffer[bufsize]));
    rbuf = &tbuf1;
    wbuf = &tbuf2;

    //** Check the length
    nbytes = segment_size(sc->src) - sc->src_offset;
    if (nbytes < 0) {
        rlen = bufsize;
    } else {
        rlen = (nbytes > bufsize) ? bufsize : nbytes;
    }
    if ((sc->len != -1) && (sc->len < nbytes)) nbytes = sc->len;

    //** Go ahead and reserve the space in the destintaion
    dend = sc->dest_offset + nbytes;
    log_printf(1, "reserving space=" XOT "\n", dend);
    gop_sync_exec(segment_truncate(sc->dest, sc->da, -dend, sc->timeout));

    //** Read the initial block
    rpos = sc->src_offset;
    wpos = sc->dest_offset;
//  rlen = (nbytes > bufsize) ? bufsize : nbytes;
    wlen = 0;
    ex_iovec_single(&rex, rpos, rlen);
    rpos += rlen;
    nbytes -= rlen;
    rgop = segment_read(sc->src, sc->da, sc->rw_hints, 1, &rex, rbuf, 0, sc->timeout);
    err = gop_waitall(rgop);
    if (err != OP_STATE_SUCCESS) {
        log_printf(1, "Intial read failed! src=%" PRIu64 " rpos=" XOT " len=" XOT "\n", segment_id(sc->src), rpos, rlen);
        gop_free(rgop, OP_DESTROY);
        return(op_failure_status);
    }
    gop_free(rgop, OP_DESTROY);

    q = new_opque();
    do {
        //** Swap the buffers
        tmpbuf = rbuf;
        rbuf = wbuf;
        wbuf = tmpbuf;
        tlen = rlen;
        rlen = wlen;
        wlen = tlen;

        log_printf(1, "sseg=" XIDT " dseg=" XIDT " wpos=%" PRId64 " rlen=%" PRId64 " wlen=%" PRId64 "\n", segment_id(sc->src), segment_id(sc->dest), wpos, rlen, wlen);

        //** Start the write
        ex_iovec_single(&wex, wpos, wlen);
        wpos += wlen;
        wgop = segment_write(sc->dest, sc->da, sc->rw_hints, 1, &wex, wbuf, 0, sc->timeout);
        opque_add(q, wgop);

        //** Read in the next block
//     rlen = (nbytes > bufsize) ? bufsize : nbytes;
        if (nbytes < 0) {
            rlen = bufsize;
        } else {
            rlen = (nbytes > bufsize) ? bufsize : nbytes;
        }
        if (rlen > 0) {
            ex_iovec_single(&rex, rpos, rlen);
            rpos += rlen;
            nbytes -= rlen;
            rgop = segment_read(sc->src, sc->da, sc->rw_hints, 1, &rex, rbuf, 0, sc->timeout);
            opque_add(q, rgop);
        }

        err = opque_waitall(q);
        if (err != OP_STATE_SUCCESS) {
            log_printf(1, "ERROR read/write failed! src=" XIDT " rpos=" XOT " len=" XOT "\n", segment_id(sc->src), rpos, rlen);
            opque_free(q, OP_DESTROY);
            return(op_failure_status);
        }
    } while (rlen > 0);

    opque_free(q, OP_DESTROY);

    if (sc->truncate == 1) {  //** Truncate if wanted
        gop_sync_exec(segment_truncate(sc->dest, sc->da, wpos, sc->timeout));
    }

    status = op_success_status;
    status.error_code = rpos;

    return(status);
}
Esempio n. 4
0
op_status_t segment_get_func(void *arg, int id)
{
    segment_copy_t *sc = (segment_copy_t *)arg;
    tbuffer_t *wbuf, *rbuf, *tmpbuf;
    tbuffer_t tbuf1, tbuf2;
    char *rb, *wb, *tb;
    ex_off_t bufsize;
    int err;
    ex_off_t rpos, wpos, rlen, wlen, tlen, nbytes, got, total;
    ex_iovec_t rex;
    apr_time_t loop_start, file_start;
    double dt_loop, dt_file;
    op_generic_t *gop;
    op_status_t status;

    //** Set up the buffers
    bufsize = sc->bufsize / 2;  //** The buffer is split for R/W
    rb = sc->buffer;
    wb = &(sc->buffer[bufsize]);
    tbuffer_single(&tbuf1, bufsize, rb);
    tbuffer_single(&tbuf2, bufsize, wb);
    rbuf = &tbuf1;
    wbuf = &tbuf2;

    status = op_success_status;

    //** Read the initial block
    rpos = sc->src_offset;
    wpos = 0;
    nbytes = segment_size(sc->src) - sc->src_offset;
    if (nbytes < 0) {
        rlen = bufsize;
    } else {
        rlen = (nbytes > bufsize) ? bufsize : nbytes;
    }

    log_printf(5, "FILE fd=%p\n", sc->fd);

    ex_iovec_single(&rex, rpos, rlen);
    wlen = 0;
    rpos += rlen;
    nbytes -= rlen;
    loop_start = apr_time_now();
    gop = segment_read(sc->src, sc->da, sc->rw_hints, 1, &rex, rbuf, 0, sc->timeout);
    err = gop_waitall(gop);
    if (err != OP_STATE_SUCCESS) {
        log_printf(1, "Intial read failed! src=" XIDT " rpos=" XOT " len=" XOT "\n", segment_id(sc->src), rpos, rlen);
        gop_free(gop, OP_DESTROY);
        return(op_failure_status);
    }
    gop_free(gop, OP_DESTROY);

    total = 0;

    do {
        //** Swap the buffers
        tb = rb;
        rb = wb;
        wb = tb;
        tmpbuf = rbuf;
        rbuf = wbuf;
        wbuf = tmpbuf;
        tlen = rlen;
        rlen = wlen;
        wlen = tlen;

        log_printf(1, "sseg=" XIDT " rpos=" XOT " wpos=" XOT " rlen=" XOT " wlen=" XOT " nbytes=" XOT "\n", segment_id(sc->src), rpos, wpos, rlen, wlen, nbytes);

        //** Read in the next block
        if (nbytes < 0) {
            rlen = bufsize;
        } else {
            rlen = (nbytes > bufsize) ? bufsize : nbytes;
        }
        if (rlen > 0) {
            ex_iovec_single(&rex, rpos, rlen);
            loop_start = apr_time_now();
            gop = segment_read(sc->src, sc->da, sc->rw_hints, 1, &rex, rbuf, 0, sc->timeout);
            gop_start_execution(gop);  //** Start doing the transfer
            rpos += rlen;
            nbytes -= rlen;
        }

        //** Start the write
        file_start = apr_time_now();
        got = fwrite(wb, 1, wlen, sc->fd);
        dt_file = apr_time_now() - file_start;
        dt_file /= (double)APR_USEC_PER_SEC;
        total += got;
        log_printf(5, "sid=" XIDT " fwrite(wb,1," XOT ", sc->fd)=" XOT " total=" XOT "\n", segment_id(sc->src), wlen, got, total);
        if (wlen != got) {
            log_printf(1, "ERROR from fread=%d  dest sid=" XIDT "\n", errno, segment_id(sc->dest));
            status = op_failure_status;
            gop_waitall(gop);
            gop_free(gop, OP_DESTROY);
            goto fail;
        }

        wpos += wlen;

        //** Wait for the read to complete
        if (rlen > 0) {
            err = gop_waitall(gop);
            gop_free(gop, OP_DESTROY);
            if (err != OP_STATE_SUCCESS) {
                log_printf(1, "ERROR write(dseg=" XIDT ") failed! wpos=" XOT " len=" XOT "\n", segment_id(sc->dest), wpos, wlen);
                status = op_failure_status;
                goto fail;
            }
        }

        dt_loop = apr_time_now() - loop_start;
        dt_loop /= (double)APR_USEC_PER_SEC;
        log_printf(1, "dt_loop=%lf  dt_file=%lf\n", dt_loop, dt_file);

    } while (rlen > 0);

fail:

    return(status);
}