svn_error_t * svn_spillbuf__read(const char **data, apr_size_t *len, svn_spillbuf_t *buf, apr_pool_t *scratch_pool) { struct memblock_t *mem; /* Possibly seek... */ SVN_ERR(maybe_seek(NULL, buf, scratch_pool)); SVN_ERR(read_data(&mem, buf, scratch_pool)); if (mem == NULL) { *data = NULL; *len = 0; } else { *data = mem->data; *len = mem->size; /* If a block was out for reading, then return it. */ if (buf->out_for_reading != NULL) return_buffer(buf, buf->out_for_reading); /* Remember that we've passed this block out for reading. */ buf->out_for_reading = mem; } return SVN_NO_ERROR; }
svn_error_t * svn_spillbuf__process(svn_boolean_t *exhausted, svn_spillbuf_t *buf, svn_spillbuf_read_t read_func, void *read_baton, apr_pool_t *scratch_pool) { svn_boolean_t has_seeked = FALSE; apr_pool_t *iterpool = svn_pool_create(scratch_pool); *exhausted = FALSE; while (TRUE) { struct memblock_t *mem; svn_error_t *err; svn_boolean_t stop; svn_pool_clear(iterpool); /* If this call to read_data() will read from the spill file, and we have not seek'd the file... then do it now. */ if (!has_seeked) SVN_ERR(maybe_seek(&has_seeked, buf, iterpool)); /* Get some content to pass to the read callback. */ SVN_ERR(read_data(&mem, buf, iterpool)); if (mem == NULL) { *exhausted = TRUE; break; } err = read_func(&stop, read_baton, mem->data, mem->size, iterpool); return_buffer(buf, mem); if (err) return svn_error_trace(err); /* If the callbacks told us to stop, then we're done for now. */ if (stop) break; } svn_pool_destroy(iterpool); return SVN_NO_ERROR; }
static bool prepare_begin_seq (s4pp_ctx_t *ctx) { clear_dict (ctx); ctx->seq.last_time = 0; ctx->seq.n_sent = 0; // SEQ:<num>,0,1,0\n - time:0 timediv:1 datafmt:0 unsigned max_buf_len = 4 + 10 + 6; char *outbuf = get_line_buffer (ctx, max_buf_len); if (!outbuf) return false; unsigned overreach = max_buf_len - sprintf (outbuf, "SEQ:%u,0,1,0\n", ctx->seq.seq_no++); return_buffer (ctx, overreach); ctx->state = S4PP_BUFFERING; init_hmac (ctx); update_hmac (ctx, ctx->authtok, strlen (ctx->authtok)); update_hmac (ctx, outbuf, max_buf_len - overreach); return true; }
static void prepare_sample_entry (s4pp_ctx_t *ctx, const s4pp_sample_t *sample, unsigned dict_idx) { unsigned val_len = sample->type == S4PP_FORMATTED ? strlen (sample->val.formatted) : (unsigned)snprintf (NULL, 0, "%f", sample->val.numeric); unsigned max_buf_len = 10 + 1 + 11 + val_len + 1 + 1; char *outbuf = get_line_buffer (ctx, max_buf_len); if (!outbuf) return; int32_t delta = sample->timestamp - ctx->seq.last_time; unsigned n; if (sample->type == S4PP_FORMATTED) n = sprintf (outbuf, "%u,%d,%s\n", dict_idx, delta, sample->val.formatted); else n = sprintf (outbuf, "%u,%d,%f\n", dict_idx, delta, sample->val.numeric); return_buffer (ctx, max_buf_len - n); ctx->seq.last_time = sample->timestamp; ++ctx->seq.n_sent; update_hmac (ctx, outbuf, n); }
static bool prepare_dict_entry (s4pp_ctx_t *ctx, const char *name, unsigned *idx) { for (dict_entry_t *d = ctx->seq.dict; d; d = d->next) { if (strcmp (name, d->name) == 0) { *idx = d->idx; return true; } } unsigned len = strlen (name); dict_entry_t *d = malloc (sizeof (dict_entry_t) + len + 1); if (!d) { ctx->state = S4PP_ERRORED; ctx->err = S4PP_NO_MEMORY; return false; } strcpy (d->name, name); d->next = ctx->seq.dict; d->idx = d->next ? d->next->idx + 1 : 0; ctx->seq.dict = d; // DICT:<idx>,,1,<name>\n unsigned max_buf_len = 5 + 10 + 4 + len + 1; char *outbuf = get_line_buffer (ctx, max_buf_len); if (!outbuf) return false; unsigned overreach = max_buf_len - sprintf (outbuf, "DICT:%u,,1,%s\n", d->idx, name); return_buffer (ctx, overreach); update_hmac (ctx, outbuf, max_buf_len - overreach); *idx = d->idx; return true; }
/* Return a memblock of content, if any is available. *mem will be NULL if no further content is available. The memblock should eventually be passed to return_buffer() (or stored into buf->out_for_reading which will grab that block at the next get_buffer() call). */ static svn_error_t * read_data(struct memblock_t **mem, svn_spillbuf_t *buf, apr_pool_t *scratch_pool) { svn_error_t *err; /* If we have some in-memory blocks, then return one. */ if (buf->head != NULL) { *mem = buf->head; if (buf->tail == *mem) buf->head = buf->tail = NULL; else buf->head = (*mem)->next; /* We're using less memory now. If we haven't hit the spill file, then we may be able to keep using memory. */ buf->memory_size -= (*mem)->size; return SVN_NO_ERROR; } /* No file? Done. */ if (buf->spill == NULL) { *mem = NULL; return SVN_NO_ERROR; } /* Assume that the caller has seeked the spill file to the correct pos. */ /* Get a buffer that we can read content into. */ *mem = get_buffer(buf); /* NOTE: mem's size/next are uninitialized. */ if ((apr_uint64_t)buf->spill_size < (apr_uint64_t)buf->blocksize) (*mem)->size = (apr_size_t)buf->spill_size; else (*mem)->size = buf->blocksize; /* The size of (*mem)->data */ (*mem)->next = NULL; /* Read some data from the spill file into the memblock. */ err = svn_io_file_read(buf->spill, (*mem)->data, &(*mem)->size, scratch_pool); if (err) { return_buffer(buf, *mem); return svn_error_trace(err); } /* Mark the data that we consumed from the spill file. */ buf->spill_start += (*mem)->size; /* Did we consume all the data from the spill file? */ if ((buf->spill_size -= (*mem)->size) == 0) { /* Close and reset our spill file information. */ SVN_ERR(svn_io_file_close(buf->spill, scratch_pool)); buf->spill = NULL; buf->spill_start = 0; } /* *mem has been initialized. Done. */ return SVN_NO_ERROR; }