Commit 30919f0d authored by Guido van Rossum's avatar Guido van Rossum

Merged the cache trace code from the branch. I'm not afraid of it any

more.  (ZEO1 will follow after lunch.)
parent 0827e4d1
...@@ -97,10 +97,11 @@ with '\0\0\0\0'. ...@@ -97,10 +97,11 @@ with '\0\0\0\0'.
If var is not writable, then temporary files are used for If var is not writable, then temporary files are used for
file 0 and file 1. file 0 and file 1.
$Id: ClientCache.py,v 1.30 2002/08/28 18:58:35 gvanrossum Exp $ $Id: ClientCache.py,v 1.31 2002/08/30 18:13:43 gvanrossum Exp $
""" """
import os import os
import time
import tempfile import tempfile
from struct import pack, unpack from struct import pack, unpack
from thread import allocate_lock from thread import allocate_lock
...@@ -185,6 +186,7 @@ class ClientCache: ...@@ -185,6 +186,7 @@ class ClientCache:
self._limit = size / 2 self._limit = size / 2
self._current = current self._current = current
self._setup_trace()
def open(self): def open(self):
# Two tasks: # Two tasks:
...@@ -230,18 +232,31 @@ class ClientCache: ...@@ -230,18 +232,31 @@ class ClientCache:
try: try:
p = self._get(oid, None) p = self._get(oid, None)
if p is None: if p is None:
self._trace(0x10, oid, version)
return None return None
f = self._f[p < 0] f = self._f[p < 0]
ap = abs(p) ap = abs(p)
f.seek(ap) f.seek(ap)
h = f.read(27) h = f.read(27)
if len(h) != 27:
log("invalidate: short record for oid %16x "
"at position %d in cache file %d"
% (U64(oid), ap, p < 0))
del self._index[oid]
return None
if h[:8] != oid: if h[:8] != oid:
return log("invalidate: oid mismatch: expected %16x read %16x "
"at position %d in cache file %d"
% (U64(oid), U64(h[:8]), ap, p < 0))
del self._index[oid]
return None
f.seek(p+8) # Switch from reading to writing f.seek(p+8) # Switch from reading to writing
if version and h[15:19] != '\0\0\0\0': if version and h[15:19] != '\0\0\0\0':
self._trace(0x1A, oid, version)
# There's still relevant non-version data in the cache record # There's still relevant non-version data in the cache record
f.write('n') f.write('n')
else: else:
self._trace(0x1C, oid, version)
del self._index[oid] del self._index[oid]
f.write('i') f.write('i')
finally: finally:
...@@ -252,6 +267,7 @@ class ClientCache: ...@@ -252,6 +267,7 @@ class ClientCache:
try: try:
p = self._get(oid, None) p = self._get(oid, None)
if p is None: if p is None:
self._trace(0x20, oid, version)
return None return None
f = self._f[p < 0] f = self._f[p < 0]
ap = abs(p) ap = abs(p)
...@@ -272,15 +288,21 @@ class ClientCache: ...@@ -272,15 +288,21 @@ class ClientCache:
if h[8]=='n': if h[8]=='n':
if version: if version:
self._trace(0x22, oid, version)
return None return None
if not dlen: if not dlen:
# XXX This shouldn't actually happen
self._trace(0x24, oid, version)
del self._index[oid] del self._index[oid]
return None return None
if not vlen or not version: if not vlen or not version:
if dlen: if dlen:
return read(dlen), h[19:] data = read(dlen)
self._trace(0x2A, oid, version, h[19:], dlen)
return data, h[19:]
else: else:
self._trace(0x26, oid, version)
return None return None
if dlen: if dlen:
...@@ -290,13 +312,17 @@ class ClientCache: ...@@ -290,13 +312,17 @@ class ClientCache:
if version != v: if version != v:
if dlen: if dlen:
seek(p+27) seek(p+27)
return read(dlen), h[19:] data = read(dlen)
self._trace(0x2C, oid, version, h[19:], dlen)
return data, h[19:]
else: else:
self._trace(0x28, oid, version)
return None return None
vdlen = unpack(">i", vheader[-4:])[0] vdlen = unpack(">i", vheader[-4:])[0]
vdata = read(vdlen) vdata = read(vdlen)
vserial = read(8) vserial = read(8)
self._trace(0x2E, oid, version, vserial, vdlen)
return vdata, vserial return vdata, vserial
finally: finally:
self._release() self._release()
...@@ -304,6 +330,7 @@ class ClientCache: ...@@ -304,6 +330,7 @@ class ClientCache:
def update(self, oid, serial, version, data): def update(self, oid, serial, version, data):
self._acquire() self._acquire()
try: try:
self._trace(0x3A, oid, version, serial, len(data))
if version: if version:
# We need to find and include non-version data # We need to find and include non-version data
p = self._get(oid, None) p = self._get(oid, None)
...@@ -345,6 +372,7 @@ class ClientCache: ...@@ -345,6 +372,7 @@ class ClientCache:
try: try:
p = self._get(oid, None) p = self._get(oid, None)
if p is None: if p is None:
self._trace(0x40, oid)
return None return None
f = self._f[p < 0] f = self._f[p < 0]
ap = abs(p) ap = abs(p)
...@@ -364,12 +392,16 @@ class ClientCache: ...@@ -364,12 +392,16 @@ class ClientCache:
return None return None
if h[8] == 'n': if h[8] == 'n':
self._trace(0x4A, oid)
return None return None
if not vlen: if not vlen:
self._trace(0x4C, oid)
return '' return ''
seek(dlen, 1) seek(dlen, 1)
return read(vlen) version = read(vlen)
self._trace(0x4E, oid, version)
return version
finally: finally:
self._release() self._release()
...@@ -381,6 +413,7 @@ class ClientCache: ...@@ -381,6 +413,7 @@ class ClientCache:
if self._pos + size > self._limit: if self._pos + size > self._limit:
current = not self._current current = not self._current
self._current = current self._current = current
self._trace(0x70)
log("flipping cache files. new current = %d" % current) log("flipping cache files. new current = %d" % current)
# Delete the half of the index that's no longer valid # Delete the half of the index that's no longer valid
index = self._index index = self._index
...@@ -406,9 +439,12 @@ class ClientCache: ...@@ -406,9 +439,12 @@ class ClientCache:
finally: finally:
self._release() self._release()
def store(self, oid, p, s, version, pv, sv): def store(self, oid, p, s, version, pv, sv):
self._acquire() self._acquire()
if s:
self._trace(0x5A, oid, version, s, len(p))
else:
self._trace(0x5C, oid, version, sv, len(pv))
try: try:
self._store(oid, p, s, version, pv, sv) self._store(oid, p, s, version, pv, sv)
finally: finally:
...@@ -446,6 +482,41 @@ class ClientCache: ...@@ -446,6 +482,41 @@ class ClientCache:
self._pos += tlen self._pos += tlen
def _setup_trace(self):
# See if cache tracing is requested through $ZEO_CACHE_TRACE.
# If not, or if we can't write to the trace file,
# disable tracing by setting self._trace to a dummy function.
self._tracefile = None
tfn = os.environ.get("ZEO_CACHE_TRACE")
if tfn:
try:
self._tracefile = open(tfn, "ab")
self._trace(0x00)
except IOError:
self._tracefile = None
if self._tracefile is None:
def notrace(*args):
pass
self._trace = notrace
def _trace(self, code, oid='', version='', serial='', dlen=0,
# Remaining arguments are speed hacks
time_time=time.time, struct_pack=pack):
# The code argument is two hex digits; bits 0 and 7 must be zero.
# The first hex digit shows the operation, the second the outcome.
# If the second digit is in "02468" then it is a 'miss'.
# If it is in "ACE" then it is a 'hit'.
# This method has been carefully tuned to be as fast as possible.
# Note: when tracing is disabled, this method is hidden by a dummy.
if version:
code |= 0x80
self._tracefile.write(
struct_pack(">ii8s8s",
time_time(),
(dlen+255) & 0x7fffff00 | code | self._current,
oid,
serial))
def read_index(index, serial, f, fileindex): def read_index(index, serial, f, fileindex):
seek = f.seek seek = f.seek
read = f.read read = f.read
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment