static svn_error_t * test_spillbuf__basic(apr_pool_t *pool, apr_size_t len, svn_spillbuf_t *buf) { int i; const char *readptr; apr_size_t readlen; /* It starts empty. */ SVN_TEST_ASSERT(svn_spillbuf__get_size(buf) == 0); /* Place enough data into the buffer to cause a spill to disk. */ for (i = 20; i--; ) SVN_ERR(svn_spillbuf__write(buf, basic_data, len, pool)); /* And now has content. */ SVN_TEST_ASSERT(svn_spillbuf__get_size(buf) > 0); /* Verify that we can read 20 copies of basic_data from the buffer. */ for (i = 20; i--; ) CHECK_READ(buf, (i + 1) * len, basic_data, pool); /* And after precisely 20 reads, it should be empty. */ SVN_ERR(svn_spillbuf__read(&readptr, &readlen, buf, pool)); SVN_TEST_ASSERT(readptr == NULL); SVN_TEST_ASSERT(svn_spillbuf__get_size(buf) == 0); return SVN_NO_ERROR; }
static svn_error_t * check_read(svn_spillbuf_t *buf, svn_filesize_t starting_size, const char *expected, apr_pool_t *scratch_pool) { apr_size_t expected_len = strlen(expected); const char *readptr; apr_size_t readlen; SVN_TEST_ASSERT(svn_spillbuf__get_size(buf) == starting_size); SVN_ERR(svn_spillbuf__read(&readptr, &readlen, buf, scratch_pool)); SVN_TEST_ASSERT(readptr != NULL && readlen == expected_len && memcmp(readptr, expected, expected_len) == 0); return SVN_NO_ERROR; }
static svn_error_t * test_spillbuf__file(apr_pool_t *pool, apr_size_t altsize, svn_spillbuf_t *buf) { int i; const char *readptr; apr_size_t readlen; apr_size_t cur_index; /* Place enough data into the buffer to cause a spill to disk. Note that we are writing data that is *smaller* than the blocksize. */ for (i = 7; i--; ) SVN_ERR(svn_spillbuf__write(buf, basic_data, sizeof(basic_data), pool)); /* The first two reads will be in-memory blocks (the third write causes the spill to disk). The spillbuf will pack the content into BLOCKSIZE blocks. The second/last memory block will (thus) be a bit smaller. */ SVN_ERR(svn_spillbuf__read(&readptr, &readlen, buf, pool)); SVN_TEST_ASSERT(readptr != NULL); SVN_TEST_ASSERT(readlen == altsize); SVN_ERR(svn_spillbuf__read(&readptr, &readlen, buf, pool)); SVN_TEST_ASSERT(readptr != NULL); /* The second write put sizeof(basic_data) into the buffer. A small portion was stored at the end of the memblock holding the first write. Thus, the size of this read will be the written data, minus that slice written to the first block. */ SVN_TEST_ASSERT(readlen == sizeof(basic_data) - (altsize - sizeof(basic_data))); /* Current index into basic_data[] that we compare against. */ cur_index = 0; while (TRUE) { /* This will read more bytes (from the spill file into a temporary in-memory block) than the blocks of data that we wrote. This makes it trickier to verify that the right data is being returned. */ SVN_ERR(svn_spillbuf__read(&readptr, &readlen, buf, pool)); if (readptr == NULL) break; while (TRUE) { apr_size_t amt; /* Compute the slice of basic_data that we will compare against, given the readlen and cur_index. */ if (cur_index + readlen >= sizeof(basic_data)) amt = sizeof(basic_data) - cur_index; else amt = readlen; SVN_TEST_ASSERT(memcmp(readptr, &basic_data[cur_index], amt) == 0); if ((cur_index += amt) == sizeof(basic_data)) cur_index = 0; if ((readlen -= amt) == 0) break; readptr += amt; } } SVN_TEST_ASSERT(svn_spillbuf__get_size(buf) == 0); return SVN_NO_ERROR; }
svn_error_t * svn_spillbuf__reader_read(apr_size_t *amt, svn_spillbuf_reader_t *reader, char *data, apr_size_t len, apr_pool_t *scratch_pool) { if (len == 0) return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, NULL); *amt = 0; while (len > 0) { apr_size_t copy_amt; if (reader->save_len > 0) { /* We have some saved content, so use this first. */ if (len < reader->save_len) copy_amt = len; else copy_amt = reader->save_len; memcpy(data, reader->save_ptr + reader->save_pos, copy_amt); reader->save_pos += copy_amt; reader->save_len -= copy_amt; } else { /* No saved content. We should now copy from spillbuf-provided buffers of content. */ /* We may need more content from the spillbuf. */ if (reader->sb_len == 0) { SVN_ERR(svn_spillbuf__read(&reader->sb_ptr, &reader->sb_len, reader->buf, scratch_pool)); /* We've run out of content, so return with whatever has been copied into DATA and stored into AMT. */ if (reader->sb_ptr == NULL) { /* For safety, read() may not have set SB_LEN. We use it as an indicator, so it needs to be cleared. */ reader->sb_len = 0; return SVN_NO_ERROR; } } if (len < reader->sb_len) copy_amt = len; else copy_amt = reader->sb_len; memcpy(data, reader->sb_ptr, copy_amt); reader->sb_ptr += copy_amt; reader->sb_len -= copy_amt; } data += copy_amt; len -= copy_amt; (*amt) += copy_amt; } return SVN_NO_ERROR; }