summaryrefslogtreecommitdiffstats
path: root/src/engine/SCons/Sig
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2002-04-09 13:49:11 (GMT)
committerSteven Knight <knight@baldmt.com>2002-04-09 13:49:11 (GMT)
commit72b58192cc6bea9962cff01f2d72e8de77591bda (patch)
tree584a5efd3d6ca331f6b3cf93d17f49055ca890df /src/engine/SCons/Sig
parent3ccdd2cb4b633d5d3603d1af53c2e578f1af8f1d (diff)
downloadSCons-72b58192cc6bea9962cff01f2d72e8de77591bda.zip
SCons-72b58192cc6bea9962cff01f2d72e8de77591bda.tar.gz
SCons-72b58192cc6bea9962cff01f2d72e8de77591bda.tar.bz2
Implement content signature caching and --max-drift (Anthony Roach)
Diffstat (limited to 'src/engine/SCons/Sig')
-rw-r--r--src/engine/SCons/Sig/SigTests.py42
-rw-r--r--src/engine/SCons/Sig/__init__.py62
2 files changed, 85 insertions, 19 deletions
diff --git a/src/engine/SCons/Sig/SigTests.py b/src/engine/SCons/Sig/SigTests.py
index 90488e1..2a2560f 100644
--- a/src/engine/SCons/Sig/SigTests.py
+++ b/src/engine/SCons/Sig/SigTests.py
@@ -99,15 +99,21 @@ class DummyNode:
def get_bsig(self):
return self.bsig
+ def store_bsig(self):
+ pass
+
def set_csig(self, csig):
self.csig = csig
def get_csig(self):
return self.csig
+ def store_csig(self):
+ pass
+
def get_prevsiginfo(self):
return (self.oldtime, self.oldbsig, self.oldcsig)
-
+
def builder_sig_adapter(self):
class Adapter:
def get_contents(self):
@@ -160,7 +166,11 @@ def write(calc, nodes):
node.oldtime = node.file.timestamp
node.oldbsig = calc.bsig(node)
node.oldcsig = calc.csig(node)
-
+
+def clear(nodes):
+ for node in nodes:
+ node.csig = None
+ node.bsig = None
class SigTestBase:
@@ -173,6 +183,7 @@ class SigTestBase:
self.test_initial()
self.test_built()
self.test_modify()
+ self.test_modify_same_time()
self.test_delete()
self.test_cache()
@@ -217,6 +228,8 @@ class SigTestBase:
self.files[6].modify('blah blah blah', 333)
self.files[8].modify('blah blah blah', 333)
+ clear(nodes)
+
self.failUnless(not current(calc, nodes[0]), "modified directly")
self.failUnless(not current(calc, nodes[1]), "direct source modified")
self.failUnless(current(calc, nodes[2]))
@@ -229,6 +242,27 @@ class SigTestBase:
self.failUnless(not current(calc, nodes[9]), "direct source modified")
self.failUnless(not current(calc, nodes[10]), "indirect source modified")
+
+ def test_modify_same_time(self):
+
+ nodes = create_nodes(self.files)
+
+ calc = SCons.Sig.Calculator(self.module, 0)
+
+ write(calc, nodes)
+
+ #simulate a modification of some files without changing the timestamp:
+ self.files[0].modify('blah blah blah blah', 333)
+ self.files[3].modify('blah blah blah blah', 333)
+ self.files[6].modify('blah blah blah blah', 333)
+ self.files[8].modify('blah blah blah blah', 333)
+
+ clear(nodes)
+
+ for node in nodes:
+ self.failUnless(current(calc, node),
+ "all of the nodes should be current")
+
def test_delete(self):
nodes = create_nodes(self.files)
@@ -306,6 +340,10 @@ class CalcTestCase(unittest.TestCase):
return 1
def get_bsig(self):
return self.bsig
+ def set_bsig(self, bsig):
+ self.bsig = bsig
+ def store_sigs(self):
+ pass
def get_csig(self):
return self.csig
def get_prevsiginfo(self):
diff --git a/src/engine/SCons/Sig/__init__.py b/src/engine/SCons/Sig/__init__.py
index cb03630..d077114 100644
--- a/src/engine/SCons/Sig/__init__.py
+++ b/src/engine/SCons/Sig/__init__.py
@@ -33,6 +33,7 @@ import os
import os.path
import string
import SCons.Node
+import time
#XXX Get rid of the global array so this becomes re-entrant.
sig_files = []
@@ -52,13 +53,13 @@ class SConsignFile:
dir - the directory for the file
module - the signature module being used
"""
-
+
self.dir = dir
self.module = module
self.sconsign = os.path.join(dir.path, '.sconsign')
self.entries = {}
self.dirty = None
-
+
try:
file = open(self.sconsign, 'rt')
except:
@@ -78,7 +79,7 @@ class SConsignFile:
filename - the filename whose signature will be returned
returns - (timestamp, bsig, csig)
"""
-
+
try:
arr = map(string.strip, string.split(self.entries[filename], " "))
except KeyError:
@@ -162,13 +163,17 @@ class Calculator:
for the build engine.
"""
- def __init__(self, module):
+ def __init__(self, module, max_drift=2*24*60*60):
"""
Initialize the calculator.
module - the signature module to use for signature calculations
+ max_drift - the maximum system clock drift used to determine when to
+ cache content signatures. A negative value means to never cache
+ content signatures. (defaults to 2 days)
"""
self.module = module
+ self.max_drift = max_drift
def bsig(self, node):
"""
@@ -185,21 +190,23 @@ class Calculator:
"""
if not node.use_signature:
return None
- #XXX If configured, use the content signatures from the
- #XXX .sconsign file if the timestamps match.
bsig = node.get_bsig()
if not bsig is None:
return bsig
- sigs = []
- for child in node.children():
- sigs.append(self.get_signature(child))
+ sigs = map(self.get_signature, node.children())
if node.builder:
sigs.append(self.module.signature(node.builder_sig_adapter()))
+ bsig = self.module.collect(filter(lambda x: not x is None, sigs))
+
+ node.set_bsig(bsig)
+
+ # don't store the bsig here, because it isn't accurate until
+ # the node is actually built.
+
+ return bsig
- return self.module.collect(filter(lambda x: not x is None, sigs))
-
def csig(self, node):
"""
Generate a node's content signature, the digested signature
@@ -210,14 +217,35 @@ class Calculator:
"""
if not node.use_signature:
return None
- #XXX If configured, use the content signatures from the
- #XXX .sconsign file if the timestamps match.
+
csig = node.get_csig()
if not csig is None:
return csig
-
- return self.module.signature(node)
-
+
+ if self.max_drift >= 0:
+ info = node.get_prevsiginfo()
+ else:
+ info = None
+
+ mtime = node.get_timestamp()
+
+ if (info and info[0] and info[2] and info[0] == mtime):
+ # use the signature stored in the .sconsign file
+ csig = info[2]
+ # Set the csig here so it doesn't get recalculated unnecessarily
+ # and so it's set when the .sconsign file gets written
+ node.set_csig(csig)
+ else:
+ csig = self.module.signature(node)
+ # Set the csig here so it doesn't get recalculated unnecessarily
+ # and so it's set when the .sconsign file gets written
+ node.set_csig(csig)
+
+ if self.max_drift >= 0 and (time.time() - mtime) > self.max_drift:
+ node.store_csig()
+
+ return csig
+
def get_signature(self, node):
"""
Get the appropriate signature for a node.
@@ -264,5 +292,5 @@ class Calculator:
if not node.builder and node.get_timestamp() == oldtime:
return 1
-
+
return self.module.current(newsig, oldbsig)