Hello,

A few weeks ago, I stumbled upon swap entry size calculation and store dir selection bug. I found more problems with the related code. One of them is discussed in this email.

Apparently, we are packing StoreEntry.swap_file_sz into the stored entry header before we compute its value. This happens because to compute swap_file_sz, we need to know swap_hdr_sz, the size of the stored entry header. To compute swap_hdr_sz, we need to pack the header, but we cannot pack the header because swap_file_sz field has not been computed yet. Chicken and egg, hidden behind a bunch of void* memcopies.

We have not noticed the problem because UFS ignores swap_file_sz (or supplies its own) in most contexts and COSS simply lacks the part of the code that would expose the bug (no store rebuilding from the disk db file).

The attached patch is a "work in progress" hack to facilitate the discussion. The patch computes the future swap_hdr_sz without packing the header, sets swap_file_sz, and then packs the header. It is not very efficient but appears to work.

If I am on the wrong path here, please shout.

Thank you,

Alex.
Work in progress: compute swap_file_sz before packing it

=== modified file 'src/StoreMeta.h'
--- src/StoreMeta.h     2009-02-01 10:09:23 +0000
+++ src/StoreMeta.h     2009-09-13 10:26:18 +0000
@@ -162,6 +162,8 @@
 /// \ingroup SwapStoreAPI
 SQUIDCEXTERN char *storeSwapMetaPack(tlv * tlv_list, int *length);
 /// \ingroup SwapStoreAPI
+SQUIDCEXTERN size_t storeSwapMetaSize(const StoreEntry * e);
+/// \ingroup SwapStoreAPI
 SQUIDCEXTERN tlv *storeSwapMetaBuild(StoreEntry * e);
 /// \ingroup SwapStoreAPI
 SQUIDCEXTERN void storeSwapTLVFree(tlv * n);

=== modified file 'src/store.cc'
--- src/store.cc        2009-09-02 05:42:24 +0000
+++ src/store.cc        2009-09-13 11:06:37 +0000
@@ -1801,12 +1801,18 @@
 char const *
 StoreEntry::getSerialisedMetaData()
 {
+    const size_t swap_hdr_sz0 = storeSwapMetaSize(this);
+    assert (swap_hdr_sz0 >= 0);
+    mem_obj->swap_hdr_sz = (size_t) swap_hdr_sz0;
+    // now we can use swap_hdr_sz to calculate swap_file_sz
+    // so that storeSwapMetaBuild/Pack can pack corrent swap_file_sz
+    swap_file_sz = objectLen() + mem_obj->swap_hdr_sz;
+
     StoreMeta *tlv_list = storeSwapMetaBuild(this);
     int swap_hdr_sz;
     char *result = storeSwapMetaPack(tlv_list, &swap_hdr_sz);
+    assert(static_cast<int>(swap_hdr_sz0) == swap_hdr_sz);
     storeSwapTLVFree(tlv_list);
-    assert (swap_hdr_sz >= 0);
-    mem_obj->swap_hdr_sz = (size_t) swap_hdr_sz;
     return result;
 }
 

=== modified file 'src/store_swapmeta.cc'
--- src/store_swapmeta.cc       2009-02-01 10:09:23 +0000
+++ src/store_swapmeta.cc       2009-09-13 11:12:46 +0000
@@ -52,6 +52,30 @@
 }
 
 /*
+ * Calculate TLV list size for a StoreEntry
+ * XXX: Must match the actual storeSwapMetaBuild result size
+ */
+size_t
+storeSwapMetaSize(const StoreEntry * e)
+{
+       size_t size = 0;
+    ++size; // STORE_META_OK
+    size += sizeof(int); // size of header to follow
+
+       const size_t pfx = sizeof(char) + sizeof(int); // in the start of list 
entries
+
+    size += pfx + SQUID_MD5_DIGEST_LENGTH;
+    size += pfx + STORE_HDR_METASIZE;
+    size += pfx + strlen(e->url()) + 1;
+
+    if (const char *vary = e->mem_obj->vary_headers)
+        size += pfx + strlen(vary) + 1;
+
+    debugs(20, 3, "storeSwapMetaSize(" << e->url() << "): " << size);
+    return size;
+}
+
+/*
  * Build a TLV list for a StoreEntry
  */
 tlv *

=== modified file 'src/store_swapout.cc'
--- src/store_swapout.cc        2009-09-02 05:53:27 +0000
+++ src/store_swapout.cc        2009-09-13 09:24:16 +0000
@@ -345,7 +345,8 @@
         debugs(20, 3, "storeSwapOutFileClosed: SwapOut complete: '" << 
e->url() << "' to " <<
                e->swap_dirn  << ", " << std::hex << std::setw(8) << 
std::setfill('0') <<
                std::uppercase << e->swap_filen);
-        e->swap_file_sz = e->objectLen() + mem->swap_hdr_sz;
+//        e->swap_file_sz = e->objectLen() + mem->swap_hdr_sz;
+assert(e->swap_file_sz == static_cast<uint64_t>(e->objectLen() + 
mem->swap_hdr_sz));
         e->swap_status = SWAPOUT_DONE;
         e->store()->updateSize(e->swap_file_sz, 1);
 

Reply via email to