summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2010-10-18 20:25:01 +0200
committerSebastian Thiel <byronimo@gmail.com>2010-10-18 20:25:01 +0200
commita7892bc7ebc99d2fe726287cc69716a3494b5ea2 (patch)
tree9365b624c5afe64bbeb17b50e89e0cc68efd0040
parent1a57dc133ec31c409819b2b40866529ed95a555b (diff)
downloadgitdb-a7892bc7ebc99d2fe726287cc69716a3494b5ea2.tar.gz
goooosh, it took so long to find a tiny nasty bug ... aarggghhh, lots of debug printing still in there, ... this one better be faster than anything else \!
-rw-r--r--_delta_apply.c182
1 files changed, 95 insertions, 87 deletions
diff --git a/_delta_apply.c b/_delta_apply.c
index 9df0191..71d5b5f 100644
--- a/_delta_apply.c
+++ b/_delta_apply.c
@@ -15,6 +15,7 @@ typedef uchar bool;
const ull gDIV_grow_by = 100;
+
// DELTA STREAM ACCESS
///////////////////////
inline
@@ -63,10 +64,14 @@ void TSI_destroy(ToplevelStreamInfo* info)
if (info->parent_object){
Py_DECREF(info->parent_object);
- info->parent_object = 0;
+ info->parent_object = NULL;
} else if (info->tds){
PyMem_Free((void*)info->tds);
}
+ info->tds = NULL;
+ info->cstart = NULL;
+ info->tdslen = 0;
+ info->num_chunks = 0;
}
inline
@@ -122,26 +127,21 @@ bool TSI_copy_stream_from_object(ToplevelStreamInfo* info)
return 1;
}
-// make sure we have the given amount of memory available. This will change
-// our official length in bytes right away, its up to the caller
-// to do something useful with the freed space
-// Return true on success
-bool TSI_resize(ToplevelStreamInfo* info, uint num_bytes)
+// Transfer ownership of the given stream into our instance. The amount of chunks
+// remains the same, and needs to be set by the caller
+void TSI_replace_stream(ToplevelStreamInfo* info, const uchar* stream, uint streamlen)
{
- assert(info->tds);
- if (num_bytes <= info->tdslen){
- return 1;
- }
+ assert(info->parent_object == 0);
+ fprintf(stderr, "TSI_replace_stream\n");
-#ifdef DEBUG
- fprintf(stderr, "TSI_resize: to %i bytes\n", num_bytes);
-#endif
uint ofs = (uint)(info->cstart - info->tds);
- info->tds = PyMem_Realloc((void*)info->tds, num_bytes);
- info->tdslen = num_bytes;
+ if (info->tds){
+ PyMem_Free((void*)info->tds);
+ }
+ info->tds = stream;
info->cstart = info->tds + ofs;
+ info->tdslen = streamlen;
- return info->tds != NULL;
}
// DELTA CHUNK
@@ -156,6 +156,9 @@ typedef struct {
const uchar* data;
} DeltaChunk;
+// forward declarations
+const uchar* next_delta_info(const uchar*, DeltaChunk*);
+
inline
void DC_init(DeltaChunk* dc, ull to, ull ts, ull so, const uchar* data)
{
@@ -208,6 +211,8 @@ inline
void DC_encode_to(const DeltaChunk* dc, uchar** pout, uint ofs, uint size)
{
uchar* out = *pout;
+ DC_print(dc, "DC_encode_to");
+ fprintf(stderr, "DC_encode_to: ofs = %i, size = %i\n" , ofs, size);
if (dc->data){
*out++ = (uchar)size;
memcpy(out, dc->data+ofs, size);
@@ -233,6 +238,18 @@ void DC_encode_to(const DeltaChunk* dc, uchar** pout, uint ofs, uint size)
*op = i;
}
+
+#ifdef DEBUG
+ DeltaChunk mdc;
+ DC_init(&mdc, 0, 0, 0, NULL);
+ next_delta_info(*pout, &mdc);
+ assert(mdc.ts == size);
+ if (mdc.data)
+ assert(mdc.data);
+ else
+ assert(mdc.so == dc->so+ofs);
+#endif
+
*pout = out;
}
@@ -497,8 +514,6 @@ DeltaInfo* DIV_closest_chunk(const DeltaInfoVector* vec, ull ofs)
return DIV_last(vec);
}
-// forward declaration
-const uchar* next_delta_info(const uchar*, DeltaChunk*);
// Return the amount of chunks a slice at the given spot would have, as well as
// its size in bytes it would have if the possibly partial chunks would be encoded
@@ -558,10 +573,11 @@ uint DIV_count_slice_bytes(const DeltaInfoVector* src, uint ofs, uint size)
// data chunk stream
// Return: number of chunks in the slice
inline
-uint DIV_copy_slice_to(const DeltaInfoVector* src, uchar* dest, ull tofs, uint size)
+uint DIV_copy_slice_to(const DeltaInfoVector* src, uchar** dest, ull tofs, uint size)
{
assert(DIV_lbound(src) <= tofs);
assert((tofs + size) <= DIV_info_rbound(src, DIV_last(src)));
+ fprintf(stderr, "copy_slice: ofs = %i, size = %i\n", (int)tofs, size);
DeltaChunk dc;
DC_init(&dc, 0, 0, 0, NULL);
@@ -573,14 +589,12 @@ uint DIV_copy_slice_to(const DeltaInfoVector* src, uchar* dest, ull tofs, uint s
if (cdi->to != tofs) {
const uint relofs = tofs - cdi->to;
next_delta_info(src->dstream + cdi->dso, &dc);
- const uint cdisize = dc.ts;
- const uint max_size = cdisize - relofs < size ? cdisize - relofs : size;
+ const uint max_size = dc.ts - relofs < size ? dc.ts - relofs : size;
size -= max_size;
// adjust dc proportions
-
- DC_encode_to(&dc, &dest, relofs, max_size);
+ DC_encode_to(&dc, dest, relofs, max_size);
num_chunks += 1;
cdi += 1;
@@ -599,10 +613,10 @@ uint DIV_copy_slice_to(const DeltaInfoVector* src, uchar* dest, ull tofs, uint s
// Full copy would be possible, but the final length of the dstream
// needs to be used as well to know how many bytes to copy
// TODO: make a DIV_ function for this
- DC_encode_to(&dc, &dest, 0, dc.ts);
+ DC_encode_to(&dc, dest, 0, dc.ts);
size -= dc.ts;
} else {
- DC_encode_to(&dc, &dest, 0, size);
+ DC_encode_to(&dc, dest, 0, size);
size = 0;
break;
}
@@ -619,98 +633,90 @@ bool DIV_connect_with_base(ToplevelStreamInfo* tsi, DeltaInfoVector* div)
{
assert(tsi->num_chunks);
- typedef struct {
- uint bofs; // byte-offset of delta stream
- uint dofs; // delta stream offset relative to tsi->cstart
- } OffsetInfo;
-
-
- OffsetInfo *const offset_array = PyMem_Malloc(tsi->num_chunks * sizeof(OffsetInfo));
- if (!offset_array){
- return 0;
- }
-
- OffsetInfo* pofs = offset_array;
- uint num_addbytes = 0;
- int bytes = 0;
- uint dofs = 0;
+ uint num_bytes = 0;
const uchar* data = TSI_first(tsi);
- const uchar* prev_data = data;
- const uchar const* dend = TSI_end(tsi);
+ const uchar* dend = TSI_end(tsi);
DeltaChunk dc;
DC_init(&dc, 0, 0, 0, NULL);
- // OFFSET RUN
- for (;data < dend; pofs++, prev_data = data)
+ // COMPUTE SIZE OF TARGET STREAM
+ /////////////////////////////////
+ for (;data < dend;)
{
- pofs->bofs = num_addbytes;
data = next_delta_info(data, &dc);
- assert(data);
- pofs->dofs = dofs;
- dofs += (uint)(data-prev_data);
+ DC_print(&dc, "count");
// Data chunks don't need processing
if (dc.data){
+ num_bytes += 1 + dc.ts;
continue;
}
- // offset the next chunk by the amount of chunks in the slice
- // - N, because we replace our own chunk's bytes
- bytes = DIV_count_slice_bytes(div, dc.so, dc.ts) - (data - prev_data);
- // if we shrink in size, compensate this by moving the start virtually
- //
- if (bytes < 0){
- fprintf(stderr, "hit negative bytes: %i\n", bytes);
- tsi->cstart += abs(bytes);
- }
- num_addbytes += abs(bytes);
+ num_bytes += DIV_count_slice_bytes(div, dc.so, dc.ts);
}
-
assert(DC_rbound(&dc) == tsi->target_size);
- // reserve enough memory to hold all the new chunks
- TSI_resize(tsi, tsi->tdslen + num_addbytes);
- const OffsetInfo const* pofs_start = offset_array - 1;
- const OffsetInfo* cpofs;
- uchar* ds; // pointer into the delta stream
- const uchar* nds; // next pointer, used for size retrieving the size
- uint num_addchunks = 0; // total amount of chunks added
+ // GET NEW DELTA BUFFER
+ ////////////////////////
+ uchar *const dstream = PyMem_Malloc(num_bytes);
+ if (!dstream){
+ return 0;
+ }
+
+
+ data = TSI_first(tsi);
+ const uchar *ndata = data;
+ dend = TSI_end(tsi);
+
+ uint num_chunks = 0;
+ uchar* ds = dstream;
DC_init(&dc, 0, 0, 0, NULL);
- // Insert slices, from the end to the beginning, which allows memcpy
- // to be used, with a little help of the offset array
- for (cpofs = pofs - 1; cpofs > pofs_start; cpofs--)
+ // pick slices from the delta and put them into the new stream
+ for (; data < dend; data = ndata)
{
- ds = (uchar*)(tsi->cstart + cpofs->dofs);
- nds = next_delta_info(ds, &dc);
+ ndata = next_delta_info(data, &dc);
+
+ DC_print(&dc, "slice");
// Data chunks don't need processing
if (dc.data){
- // NOTE: could peek the preceeding chunks to figure out whether they are
- // all just moved by ofs. In that case, they can move as a whole!
- // tests showed that this is very rare though, even in huge deltas, so its
- // not worth the extra effort
- if (cpofs->bofs){
- memcpy((void*)(ds + cpofs->bofs), (void*)ds, nds - ds);
- // memmove((void*)(ds + cpofs->bofs), (void*)ds, nds - ds);
- }
+ // just copy it over
+ memcpy((void*)ds, (void*)data, ndata - data);
+ ds += ndata - data;
+ num_chunks += 1;
continue;
}
- // Copy Chunks - target offset is determined by their location and size
- // hence it doesn't need specific adjustment
- num_addchunks += DIV_copy_slice_to(div, ds + cpofs->bofs, dc.so, dc.ts);
- // -1 chunks because we overwrite our own chunk ( by not copying it )
- num_addchunks -= 1;
+ // Copy Chunks
+ num_chunks += DIV_copy_slice_to(div, &ds, dc.so, dc.ts);
}
+ assert(ds - dstream == num_bytes);
+ assert(num_chunks >= tsi->num_chunks);
+ assert(DC_rbound(&dc) == tsi->target_size);
+
+ // finally, replace the streams
+ TSI_replace_stream(tsi, dstream, num_bytes);
+ tsi->cstart = dstream; // we have NO header !
+ assert(tsi->tds == dstream);
+ tsi->num_chunks = num_chunks;
- tsi->num_chunks += num_addchunks;
+#ifdef DEBUG
+ data = TSI_first(tsi);
+ dend = TSI_end(tsi);
+
+ DC_init(&dc, 0, 0, 0, NULL);
+
+ while (data < dend){
+ data = next_delta_info(data, &dc);
+ DC_print(&dc, "debug");
+ }
+#endif
- PyMem_Free(offset_array);
return 1;
}
@@ -754,6 +760,7 @@ PyObject* DCL_py_rbound(DeltaChunkList* self)
static
PyObject* DCL_apply(DeltaChunkList* self, PyObject* args)
{
+ fprintf(stderr, "DCL_apply\n");
PyObject* pybuf = 0;
PyObject* writeproc = 0;
@@ -890,6 +897,7 @@ const uchar* next_delta_info(const uchar* data, DeltaChunk* dc)
data += cmd;
} else {
PyErr_SetString(PyExc_RuntimeError, "Encountered an unsupported delta cmd: 0");
+ assert(0);
return NULL;
}
@@ -1048,7 +1056,7 @@ static PyObject* connect_deltas(PyObject *self, PyObject *dstreams)
#ifdef DEBUG
fprintf(stderr, "------------ Stream %i --------\n ", (int)dsi);
- fprintf(stderr, "Before Connect: tdsinfo->num_chunks = %i, tdsinfo->bytelen = %i\n", (int)tdsinfo.num_chunks, (int)tdsinfo.tdslen);
+ fprintf(stderr, "Before Connect: tdsinfo: num_chunks = %i, bytelen = %i, target_size = %i\n", (int)tdsinfo.num_chunks, (int)tdsinfo.tdslen, (int)tdsinfo.target_size);
fprintf(stderr, "div->num_chunks = %i, div->reserved_size = %i, div->bytelen=%i\n", (int)div.size, (int)div.reserved_size, (int)dlen);
#endif