/*
- * $Id: MemObject.cc,v 1.12 2003/08/10 05:11:22 robertc Exp $
+ * $Id$
*
* DEBUG: section 19 Store Memory Primitives
* AUTHOR: Robert Collins
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
*
*/
-#include "squid.h"
+#include "squid-old.h"
+#include "comm/Connection.h"
#include "MemObject.h"
#include "HttpRequest.h"
#include "HttpReply.h"
#include "Store.h"
#include "StoreClient.h"
#include "Generic.h"
-#if DELAY_POOLS
+#if USE_DELAY_POOLS
#include "DelayPools.h"
#endif
+#include "MemBuf.h"
/* TODO: make this global or private */
#if URL_CHECKSUM_DEBUG
url_checksum(const char *url)
{
unsigned int ck;
- MD5_CTX M;
+ SquidMD5_CTX M;
static unsigned char digest[16];
- MD5Init(&M);
- MD5Update(&M, (unsigned char *) url, strlen(url));
- MD5Final(digest, &M);
- xmemcpy(&ck, digest, sizeof(ck));
+ SquidMD5Init(&M);
+ SquidMD5Update(&M, (unsigned char *) url, strlen(url));
+ SquidMD5Final(digest, &M);
+ memcpy(&ck, digest, sizeof(ck));
return ck;
}
#endif
-MemPool *MemObject::pool = NULL;
+RemovalPolicy * mem_policy = NULL;
-void *
-MemObject::operator new (size_t byteCount)
+size_t
+MemObject::inUseCount()
{
- /* derived classes with different sizes must implement their own new */
- assert (byteCount == sizeof (MemObject));
-
- if (!pool)
- pool = memPoolCreate("MemObject", sizeof (MemObject));
-
- return memPoolAlloc(pool);
+ return Pool().inUseCount();
}
void
-MemObject::operator delete (void *address)
+MemObject::resetUrls(char const *aUrl, char const *aLog_url)
{
- memPoolFree(pool, address);
+ safe_free(url);
+ safe_free(log_url); /* XXX account log_url */
+ log_url = xstrdup(aLog_url);
+ url = xstrdup(aUrl);
}
-size_t
-MemObject::inUseCount()
+MemObject::MemObject(char const *aUrl, char const *aLog_url)
{
- if (!pool)
- return 0;
-
- MemPoolStats stats;
-
- memPoolGetStats (&stats, pool);
-
- return stats.items_inuse;
-}
+ debugs(20, 3, HERE << "new MemObject " << this);
+ HttpReply *rep = new HttpReply;
-MemObject::MemObject(char const *aUrl, char const *aLog_url) :
- _reply (httpReplyCreate())
-{
+ _reply = HTTPMSGLOCK(rep);
url = xstrdup(aUrl);
+
#if URL_CHECKSUM_DEBUG
chksum = url_checksum(url);
+
#endif
log_url = xstrdup(aLog_url);
+
object_sz = -1;
+
/* XXX account log_url */
- debug(20, 3) ("MemObject::MemObject: initialized %p\n", this);
+
+ swapout.decision = SwapOut::swNeedsCheck;
}
MemObject::~MemObject()
{
+ debugs(20, 3, HERE << "del MemObject " << this);
const Ctx ctx = ctx_enter(url);
- debug(20, 3) ("destroy_MemObject: destroying %p\n", this);
#if URL_CHECKSUM_DEBUG
assert(chksum == url_checksum(url));
#endif
- httpReplyDestroy((HttpReply *)_reply);
-
- requestUnlink(request);
+ HTTPMSGUNLOCK(_reply);
- request = NULL;
+ HTTPMSGUNLOCK(request);
ctx_exit(ctx); /* must exit before we free mem->url */
void
MemObject::unlinkRequest()
{
- /* XXX Should we assert(request)? */
- requestUnlink(request);
- request = NULL;
+ HTTPMSGUNLOCK(request);
}
void
MemObject::write ( StoreIOBuffer writeBuffer, STMCB *callback, void *callbackData)
{
PROF_start(MemObject_write);
- debug(19, 6) ("memWrite: offset %lu len %ld\n", (unsigned long)writeBuffer.offset, (long)writeBuffer.length);
+ debugs(19, 6, "memWrite: offset " << writeBuffer.offset << " len " << writeBuffer.length);
/* the offset is into the content, not the headers */
writeBuffer.offset += (_reply ? _reply->hdr_sz : 0);
/* We don't separate out mime headers yet, so ensure that the first
- * write is at offset 0 - where they start
+ * write is at offset 0 - where they start
*/
assert (data_hdr.endOffset() || writeBuffer.offset == 0);
data_hdr.dump();
#if 0
/* do we want this one? */
- debug(20, 1) ("MemObject->data.origin_offset: %d\n",
- data_hdr.head ? data_hdr.head->nodeBuffer.offset : 0);
+ debugs(20, 1, "MemObject->data.origin_offset: " << (data_hdr.head ? data_hdr.head->nodeBuffer.offset : 0));
#endif
- debug(20, 1) ("MemObject->start_ping: %d.%06d\n",
- (int) start_ping.tv_sec,
- (int) start_ping.tv_usec);
- debug(20, 1) ("MemObject->inmem_hi: %d\n",
- (int) data_hdr.endOffset());
- debug(20, 1) ("MemObject->inmem_lo: %d\n",
- (int) inmem_lo);
- debug(20, 1) ("MemObject->nclients: %d\n",
- nclients);
- debug(20, 1) ("MemObject->reply: %p\n",
- _reply);
- debug(20, 1) ("MemObject->request: %p\n",
- request);
- debug(20, 1) ("MemObject->log_url: %p %s\n",
- log_url,
- checkNullString(log_url));
+ debugs(20, 1, "MemObject->start_ping: " << start_ping.tv_sec << "."<< std::setfill('0') << std::setw(6) << start_ping.tv_usec);
+ debugs(20, 1, "MemObject->inmem_hi: " << data_hdr.endOffset());
+ debugs(20, 1, "MemObject->inmem_lo: " << inmem_lo);
+ debugs(20, 1, "MemObject->nclients: " << nclients);
+ debugs(20, 1, "MemObject->reply: " << _reply);
+ debugs(20, 1, "MemObject->request: " << request);
+ debugs(20, 1, "MemObject->log_url: " << log_url << " " << checkNullString(log_url));
}
HttpReply const *
return _reply;
}
-struct LowestMemReader : public unary_function<store_client, void>
+void
+MemObject::replaceHttpReply(HttpReply *newrep)
{
- LowestMemReader(off_t seed):current(seed){}
+ HTTPMSGUNLOCK(_reply);
+ _reply = HTTPMSGLOCK(newrep);
+}
+
+struct LowestMemReader : public unary_function<store_client, void> {
+ LowestMemReader(int64_t seed):current(seed) {}
- void operator() (store_client const &x)
- {
+ void operator() (store_client const &x) {
if (x.memReaderHasLowerOffset(current))
current = x.copyInto.offset;
}
- off_t current;
+ int64_t current;
};
-struct StoreClientStats : public unary_function<store_client, void>
-{
- StoreClientStats(StoreEntry *anEntry):where(anEntry),index(0){}
+struct StoreClientStats : public unary_function<store_client, void> {
+ StoreClientStats(MemBuf *anEntry):where(anEntry),index(0) {}
- void operator()(store_client const &x)
- {
+ void operator()(store_client const &x) {
x.dumpStats(where, index++);
}
- StoreEntry *where;
+ MemBuf *where;
size_t index;
};
void
-MemObject::stat (StoreEntry *s) const
+MemObject::stat(MemBuf * mb) const
{
- storeAppendPrintf(s, "\t%s %s\n",
- RequestMethodStr[method], log_url);
- storeAppendPrintf(s, "\tinmem_lo: %d\n", (int) inmem_lo);
- storeAppendPrintf(s, "\tinmem_hi: %d\n", (int) data_hdr.endOffset());
- storeAppendPrintf(s, "\tswapout: %d bytes queued\n",
- (int) swapout.queue_offset);
+ mb->Printf("\t%s %s\n",
+ RequestMethodStr(method), log_url);
+ if (vary_headers)
+ mb->Printf("\tvary_headers: %s\n", vary_headers);
+ mb->Printf("\tinmem_lo: %"PRId64"\n", inmem_lo);
+ mb->Printf("\tinmem_hi: %"PRId64"\n", data_hdr.endOffset());
+ mb->Printf("\tswapout: %"PRId64" bytes queued\n",
+ swapout.queue_offset);
if (swapout.sio.getRaw())
- storeAppendPrintf(s, "\tswapout: %d bytes written\n",
- (int) swapout.sio->offset());
+ mb->Printf("\tswapout: %"PRId64" bytes written\n",
+ (int64_t) swapout.sio->offset());
- StoreClientStats statsVisitor(s);
+ StoreClientStats statsVisitor(mb);
for_each<StoreClientStats>(clients, statsVisitor);
}
-off_t
+int64_t
MemObject::endOffset () const
{
return data_hdr.endOffset();
}
-size_t
+void
+MemObject::markEndOfReplyHeaders()
+{
+ const int hdr_sz = endOffset();
+ assert(hdr_sz >= 0);
+ assert(_reply);
+ _reply->hdr_sz = hdr_sz;
+}
+
+int64_t
MemObject::size() const
{
if (object_sz < 0)
return object_sz;
}
+int64_t
+MemObject::expectedReplySize() const
+{
+ debugs(20, 7, HERE << "object_sz: " << object_sz);
+ if (object_sz >= 0) // complete() has been called; we know the exact answer
+ return object_sz;
+
+ if (_reply) {
+ const int64_t clen = _reply->bodySize(method);
+ debugs(20, 7, HERE << "clen: " << clen);
+ if (clen >= 0 && _reply->hdr_sz > 0) // yuck: HttpMsg sets hdr_sz to 0
+ return clen + _reply->hdr_sz;
+ }
+
+ return -1; // not enough information to predict
+}
+
void
MemObject::reset()
{
}
-off_t
+int64_t
MemObject::lowestMemReaderOffset() const
{
LowestMemReader lowest (endOffset() + 1);
bool
MemObject::readAheadPolicyCanRead() const
{
- return (size_t)endOffset() - getReply()->hdr_sz < lowestMemReaderOffset() + (Config.readAheadGap << 10);
+ return endOffset() - getReply()->hdr_sz < lowestMemReaderOffset() + Config.readAheadGap;
}
void
/*
* How much of the object data is on the disk?
*/
-size_t
+int64_t
MemObject::objectBytesOnDisk() const
{
/*
* NOTE: storeOffset() represents the disk file size,
* not the amount of object data on disk.
- *
+ *
* If we don't have at least 'swap_hdr_sz' bytes
* then none of the object data is on disk.
*
if (swapout.sio.getRaw() == NULL)
return 0;
- off_t nwritten = swapout.sio->offset();
+ int64_t nwritten = swapout.sio->offset();
- if (nwritten <= (off_t)swap_hdr_sz)
+ if (nwritten <= (int64_t)swap_hdr_sz)
return 0;
- return (size_t) (nwritten - swap_hdr_sz);
+ return (nwritten - swap_hdr_sz);
}
-off_t
-MemObject::policyLowestOffsetToKeep() const
+int64_t
+MemObject::policyLowestOffsetToKeep(bool swap) const
{
/*
* Careful. lowest_offset can be greater than endOffset(), such
* as in the case of a range request.
*/
- off_t lowest_offset = lowestMemReaderOffset();
+ int64_t lowest_offset = lowestMemReaderOffset();
if (endOffset() < lowest_offset ||
- endOffset() - inmem_lo > (ssize_t)Config.Store.maxInMemObjSize)
+ endOffset() - inmem_lo > (int64_t)Config.Store.maxInMemObjSize ||
+ (swap && !Config.onoff.memory_cache_first))
return lowest_offset;
return inmem_lo;
void
MemObject::trimSwappable()
{
- off_t new_mem_lo = policyLowestOffsetToKeep();
+ int64_t new_mem_lo = policyLowestOffsetToKeep(1);
/*
* We should only free up to what we know has been written
* to disk, not what has been queued for writing. Otherwise
* there will be a chunk of the data which is not in memory
* and is not yet on disk.
* The -1 makes sure the page isn't freed until storeSwapOut has
- * walked to the next page. (mem->swapout.memnode)
+ * walked to the next page.
*/
- off_t on_disk;
+ int64_t on_disk;
if ((on_disk = objectBytesOnDisk()) - 1 < new_mem_lo)
new_mem_lo = on_disk - 1;
void
MemObject::trimUnSwappable()
{
- off_t new_mem_lo = policyLowestOffsetToKeep();
+ int64_t new_mem_lo = policyLowestOffsetToKeep(0);
assert (new_mem_lo > 0);
data_hdr.freeDataUpto(new_mem_lo);
bool
MemObject::isContiguous() const
{
- bool result = data_hdr.hasContigousContentRange (Range<size_t>(inmem_lo, endOffset()));
+ bool result = data_hdr.hasContigousContentRange (Range<int64_t>(inmem_lo, endOffset()));
/* XXX : make this higher level */
- debug (19, result ? 4 :3) ("MemObject::isContiguous: Returning %s\n",
- result ? "true" : "false");
+ debugs (19, result ? 4 :3, "MemObject::isContiguous: Returning " << (result ? "true" : "false"));
return result;
}
int
MemObject::mostBytesWanted(int max) const
{
-#if DELAY_POOLS
+#if USE_DELAY_POOLS
/* identify delay id with largest allowance */
DelayId largestAllowance = mostBytesAllowed ();
return largestAllowance.bytesWanted(0, max);
void
MemObject::setNoDelay(bool const newValue)
{
-#if DELAY_POOLS
+#if USE_DELAY_POOLS
for (dlink_node *node = clients.head; node; node = node->next) {
store_client *sc = (store_client *) node->data;
deferredReads.kickReads(-1);
}
-#if DELAY_POOLS
+#if USE_DELAY_POOLS
DelayId
MemObject::mostBytesAllowed() const
{
}
#endif
+
+int64_t
+MemObject::availableForSwapOut() const
+{
+ return endOffset() - swapout.queue_offset;
+}