void Async::upload_file( Disk disk, const Dirent& ent, Stream* stream, on_after_func callback, const size_t CHUNK_SIZE) { disk_transfer(disk, ent, [stream] (fs::buffer_t buffer, next_func next) mutable { auto length = buffer->size(); // temp stream->on_write( net::tcp::Connection::WriteCallback::make_packed( [length, next] (size_t n) { // if all data written, go to next chunk debug("<Async::upload_file> %u / %u\n", n, length); next(n == length); }) ); // write chunk to TCP connection stream->write(buffer); }, callback, CHUNK_SIZE); }
/* \param xdf pointer to a valid xdffile with mode XDF_READ * \param offset offset where the current sample pointer must move * \param whence reference of the offset * * API FUNCTION * Reposition the current sample pointer according to the couple * (offset, whence). whence can be SEEK_SET, SEEK_CUR or SEEK_END * Upon successful completion, it returns the resulting offset location as * measured in number of samples for the begining of the recording. * Otherwise -1 is returned and errno is set to indicate the error */ API_EXPORTED off_t xdf_seek(struct xdf* xdf, off_t offset, int whence) { off_t curpoint, reqpoint, fileoff; int irec, errnum = 0; unsigned int nsprec = xdf->ns_per_rec; if (!xdf || (xdf->mode != XDF_READ) || (!xdf->ready)) { errno = xdf ? EPERM : EINVAL; return -1; } curpoint = (xdf->nrecread < 0 ? 0 : xdf->nrecread)*nsprec - xdf->ns_buff; if (whence == SEEK_CUR) reqpoint = curpoint + offset; else if (whence == SEEK_SET) reqpoint = offset; else if (whence == SEEK_END) reqpoint = xdf->nrecord * nsprec + offset; else return xdf_set_error(EINVAL); if (reqpoint < 0 || (reqpoint >= (off_t)(xdf->nrecord * nsprec))) return xdf_set_error(ERANGE); irec = reqpoint / nsprec; if (irec != xdf->nrecread) { if (irec != xdf->nrecread + 1) { pthread_mutex_lock(&(xdf->mtx)); // Wait for the previous operation to be finished while (xdf->order && !xdf->reportval) pthread_cond_wait(&(xdf->cond), &(xdf->mtx)); fileoff = irec*xdf->filerec_size + xdf->hdr_offset; if ( (lseek(xdf->fd, fileoff, SEEK_SET) < 0) || (read_diskrec(xdf)) ) errnum = errno; pthread_mutex_unlock(&(xdf->mtx)); if (errnum) return xdf_set_error(errnum); } if (disk_transfer(xdf)) return -1; xdf->nrecread = irec; } xdf->ns_buff = nsprec - reqpoint%nsprec; return reqpoint; }
/* \param xdf pointer of a valid xdf file with mode XDF_WRITE * * Fill the remaining of the current record with 0 and transfer it. This * ensures that no previous data will added be truncated because of the end. */ static int finish_record(struct xdf* xdf) { char* buffer = xdf->buff + xdf->sample_size * xdf->ns_buff; unsigned int ns = xdf->ns_per_rec - xdf->ns_buff; if (!xdf->ns_buff) return 0; // Fill the remaining of the record with 0 values while (ns--) { memset(buffer, 0, xdf->sample_size); buffer += xdf->sample_size; } return disk_transfer(xdf); }
/* \param xdf pointer to a valid xdffile with mode XDF_READ * \param ns number of samples to be read * \param other pointer to the arrays holding the output samples * * API FUNCTION * Read samples in the buffer and transfer them to one or several output * arrays. The number of arrays that must be provided on the call depends * on the specification of the channels. * Returns the number of samples read, -1 in case of error */ API_EXPORTED ssize_t xdf_read(struct xdf* xdf, size_t ns, ...) { if ((xdf == NULL) || !xdf->ready || (xdf->mode == XDF_WRITE)) { errno = (xdf == NULL) ? EINVAL : EPERM; return -1; } unsigned int i, k, ia; unsigned int nbatch = xdf->nbatch, samsize = xdf->sample_size; char* restrict buff = xdf->buff + samsize * (xdf->ns_per_rec-xdf->ns_buff); struct data_batch* batch = xdf->batch; char* restrict out[xdf->narrays]; va_list ap; int ret; // Initialization of the output buffers va_start(ap, ns); for (ia=0; ia<xdf->narrays; ia++) out[ia] = va_arg(ap, char*); va_end(ap); for (i=0; i<ns; i++) { // Trigger a disk read when the content of buffer is empty if (!xdf->ns_buff) { if ((ret = disk_transfer(xdf))) return ((ret<0)&&(i==0)) ? -1 : (ssize_t)i; buff = xdf->buff; xdf->ns_buff = xdf->ns_per_rec; xdf->nrecread++; } // Transfer the sample to the buffer by chunk for (k=0; k < nbatch; k++) { ia = batch[k].iarray; memcpy(out[ia], buff+batch[k].foff, batch[k].len); out[ia] += batch[k].mskip; } buff += samsize; xdf->ns_buff--; } return ns; }
/* \param xdf pointer to a valid xdffile with mode XDF_WRITE * \param ns number of samples to be added * \param other pointer to the arrays holding the input samples * * API FUNCTION * Add samples coming from one or several input arrays containing the * samples. The number of arrays that must be provided on the call depends * on the specification of the channels. * Returns the number of samples written, -1 in case of error */ API_EXPORTED ssize_t xdf_write(struct xdf* xdf, size_t ns, ...) { if ((xdf == NULL) || !xdf->ready || (xdf->mode == XDF_READ)) { errno = (xdf == NULL) ? EINVAL : EPERM; return -1; } unsigned int i, k, ia, nsrec = xdf->ns_per_rec; unsigned int nbatch = xdf->nbatch, samsize = xdf->sample_size; char* restrict buff = xdf->buff + samsize * xdf->ns_buff; struct data_batch* batch = xdf->batch; const char* restrict in[xdf->narrays]; va_list ap; // Initialization of the input buffers va_start(ap, ns); for (ia=0; ia<xdf->narrays; ia++) in[ia] = va_arg(ap, const char*); va_end(ap); for (i=0; i<ns; i++) { // Write the content of the buffer if full if (xdf->ns_buff == nsrec) { if (disk_transfer(xdf)) return (i==0) ? -1 : (ssize_t)i; buff = xdf->buff; xdf->ns_buff = 0; } // Transfer the sample to the buffer by chunk for (k=0; k<nbatch; k++) { ia = batch[k].iarray; memcpy(buff+batch[k].foff, in[ia], batch[k].len); in[ia] += batch[k].mskip; } buff += samsize; xdf->ns_buff++; } return (ssize_t)ns; }
/* \param xdf pointer to a valid xdf file * * API FUNCTION * Compute the batches, allocate the necessary data for the transfer and * Initialize the transfer thread */ API_EXPORTED int xdf_prepare_transfer(struct xdf* xdf) { int nbatch; if (xdf->ready) return -1; // Just compute the number of batch (no mem allocated for them yet) if ( (nbatch = compute_batches(xdf, 0)) < 0 ) goto error; xdf->nbatch = nbatch; // Alloc of temporary entities needed for convertion if (alloc_transfer_objects(xdf)) goto error; // Setup batches, convertion parameters compute_batches(xdf, 1); // assign batches: memory is now allocated setup_convdata(xdf); if (xdf->mode == XDF_WRITE) { if (init_file_content(xdf)) goto error; } if (init_transfer_thread(xdf)) goto error; if (xdf->mode == XDF_READ) { disk_transfer(xdf); xdf->nrecread = -1; } xdf->ready = 1; return 0; error: free_transfer_objects(xdf); xdf->nbatch = 0; return -1; }
void Async::upload_file( Disk disk, const Dirent& ent, Connection conn, on_after_func callback, const size_t CHUNK_SIZE) { disk_transfer(disk, ent, [conn] (fs::buffer_t buffer, size_t length, next_func next) { // write chunk to TCP connection conn->write(buffer.get(), length, [length, next] (size_t n) { // if all data written, go to next chunk debug("sock write: %u / %u\n", n, length); next(n == length); }, true); }, callback, CHUNK_SIZE); }