Switch to side-by-side view

--- a/src/utils/circache.cpp
+++ b/src/utils/circache.cpp
@@ -614,36 +614,80 @@
     return m_d ? m_d->m_reason.str() : "Not initialized";
 }
 
-bool CirCache::create(off_t m_maxsize, int flags)
-{
-    LOGDEB(("CirCache::create: [%s] flags 0x%x\n", m_dir.c_str(), flags));
+// A scan callback which just records the last header offset and
+// padsize seen. This is used with a scan(nofold) to find the last
+// physical record in the file
+class CCScanHookRecord : public  CCScanHook {
+public:
+    off_t headoffs;
+    off_t padsize;
+    CCScanHookRecord()
+	: headoffs(0), padsize(0)
+    {
+    }
+    virtual status takeone(off_t offs, const string& udi, 
+			   const EntryHeaderData& d)
+    {
+	headoffs = offs;
+	padsize = d.padsize;
+	LOGDEB2(("CCScanHookRecord::takeone: offs %lld padsize %lld\n", 
+		 headoffs, padsize));
+        return Continue;
+    }
+};
+
+bool CirCache::create(off_t maxsize, int flags)
+{
+    LOGDEB(("CirCache::create: [%s] maxsz %lld flags 0x%x\n", 
+	    m_dir.c_str(), maxsize, flags));
     if (m_d == 0) {
 	LOGERR(("CirCache::create: null data\n"));
 	return false;
     }
 
-    {
-	struct stat st;
-	if (stat(m_dir.c_str(), &st) < 0) {
-	    // Directory does not exist, create it
-	    if (mkdir(m_dir.c_str(), 0777) < 0) {
-		m_d->m_reason << "CirCache::create: mkdir(" << m_dir << 
-		    ") failed" << " errno " << errno;
+    struct stat st;
+    if (stat(m_dir.c_str(), &st) < 0) {
+	// Directory does not exist, create it
+	if (mkdir(m_dir.c_str(), 0777) < 0) {
+	    m_d->m_reason << "CirCache::create: mkdir(" << m_dir << 
+		") failed" << " errno " << errno;
+	    return false;
+	}
+    } else {
+	// If the file exists too, and truncate is not set, switch
+	// to open-mode. Still may need to update header params.
+	if (access(m_d->datafn(m_dir).c_str(), 0) >= 0 &&
+	    !(flags & CC_CRTRUNCATE)) {
+	    if (!open(CC_OPWRITE)) {
 		return false;
 	    }
-	} else {
-	    // Directory exists but file might still not exist:
-	    // e.g. the user is using a non default directory and
-	    // created it for us.
-	    if (access(m_d->datafn(m_dir).c_str(), 0) >= 0) {
-		// File exists, switch to "open" mode, except if we're told to 
-		// truncate.
-		if (!(flags & CC_CRTRUNCATE)) {
-		    return open(CC_OPWRITE);
-		}
+	    if (maxsize == m_d->m_maxsize &&
+		((flags & CC_CRUNIQUE) != 0) == m_d->m_uniquentries) {
+		LOGDEB(("Header unchanged, no rewrite\n"));
+		return true;
 	    }
-	    // Else fall through to create file
-	}
+	    // If the new maxsize is bigger than current size, we need
+	    // to stop recycling if this is what we are doing.
+	    if (maxsize > m_d->m_maxsize && maxsize > st.st_size) {
+		// Scan the file to find the last physical record. The
+		// ohead is set at physical eof, and nhead is the last
+		// scanned record
+		CCScanHookRecord rec;
+		m_d->scan(CIRCACHE_FIRSTBLOCK_SIZE, &rec, false);
+		m_d->m_oheadoffs = lseek(m_d->m_fd, 0, SEEK_END);
+		m_d->m_nheadoffs = rec.headoffs;
+		m_d->m_npadsize = rec.padsize;
+	    }
+	    m_d->m_maxsize = maxsize;
+	    m_d->m_uniquentries = ((flags & CC_CRUNIQUE) != 0);
+	    LOGDEB(("CirCache::create: rewriting header with "
+		    "maxsize %lld oheadoffs %lld nheadoffs %lld "
+		    "npadsize %d unient %d\n",
+		    m_d->m_maxsize, m_d->m_oheadoffs, m_d->m_nheadoffs,
+		    m_d->m_npadsize, int(m_d->m_uniquentries)));
+	    return m_d->writefirstblock();
+	}
+	// Else fallthrough to create file
     }
 
     if ((m_d->m_fd = ::open(m_d->datafn(m_dir).c_str(), 
@@ -653,7 +697,7 @@
 	return false;
     }
 
-    m_d->m_maxsize = m_maxsize;
+    m_d->m_maxsize = maxsize;
     m_d->m_oheadoffs = CIRCACHE_FIRSTBLOCK_SIZE;
     m_d->m_uniquentries = ((flags & CC_CRUNIQUE) != 0);