changeset 111:d7eb7bf188ed

simplify revision timestamp handling - just store it into metadata Back when the storage api was implemented, timestamp was implemented as a property. I can't remember why this was done, but I assume it was to do backend-specific optimization to quickly access revision timestamp without accessing metadata. As we'll have an index for most important metadata and we likely have to open metadata anyway, MTIME is now just a metadata entry like all the others, not specialcased any more. Like the revision data hash, MTIME is also automatically stored into the revision's metadata when committing it. This simplifies the code quite a bit and makes it more generic.
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Sat, 12 Mar 2011 23:33:46 +0100
parents 713df2332b89
children 1efaef3eec9c
files MoinMoin/config/__init__.py MoinMoin/items/__init__.py MoinMoin/storage/__init__.py MoinMoin/storage/_tests/test_backends.py MoinMoin/storage/_tests/test_backends_hg.py MoinMoin/storage/_tests/test_serialization.py MoinMoin/storage/backends/_flatutils.py MoinMoin/storage/backends/acl.py MoinMoin/storage/backends/fileserver.py MoinMoin/storage/backends/flatfile.py MoinMoin/storage/backends/fs.py MoinMoin/storage/backends/fs19.py MoinMoin/storage/backends/fs2.py MoinMoin/storage/backends/hg.py MoinMoin/storage/backends/indexing.py MoinMoin/storage/backends/memory.py MoinMoin/storage/backends/router.py MoinMoin/storage/backends/sqla.py
diffstat 18 files changed, 64 insertions(+), 116 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/config/__init__.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/config/__init__.py	Sat Mar 12 23:33:46 2011 +0100
@@ -104,6 +104,7 @@
 ADDRESS = "address"
 HOSTNAME = "hostname"
 USERID = "userid"
+MTIME = "mtime"
 EXTRA = "extra"
 COMMENT = "comment"
 
--- a/MoinMoin/items/__init__.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/items/__init__.py	Sat Mar 12 23:33:46 2011 +0100
@@ -51,7 +51,7 @@
 from MoinMoin.util.send_file import send_file
 from MoinMoin.storage.error import NoSuchItemError, NoSuchRevisionError, AccessDeniedError, \
                                    StorageError
-from MoinMoin.config import UUID, NAME, NAME_OLD, REVERTED_TO, ACL, \
+from MoinMoin.config import UUID, NAME, NAME_OLD, MTIME, REVERTED_TO, ACL, \
                             IS_SYSITEM, SYSITEM_VERSION,  USERGROUP, SOMEDICT, \
                             MIMETYPE, SIZE, LANGUAGE, ITEMLINKS, ITEMTRANSCLUSIONS, \
                             TAGS, ACTION, ADDRESS, HOSTNAME, USERID, EXTRA, COMMENT, \
@@ -283,6 +283,7 @@
                      HASH_ALGORITHM,
                      SIZE,
                      COMMENT,
+                     MTIME,
                      ACTION,
                      ADDRESS, HOSTNAME, USERID,
                     ]
--- a/MoinMoin/storage/__init__.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/__init__.py	Sat Mar 12 23:33:46 2011 +0100
@@ -42,6 +42,7 @@
 import os
 import sys
 import shutil
+import time
 
 from MoinMoin import log
 logging = log.getLogger(__name__)
@@ -51,7 +52,7 @@
                                    BackendError, NoSuchItemError, \
                                    RevisionAlreadyExistsError, ItemAlreadyExistsError
 
-from MoinMoin.config import SIZE, HASH_ALGORITHM
+from MoinMoin.config import SIZE, MTIME, HASH_ALGORITHM
 
 import hashlib
 
@@ -402,18 +403,6 @@
         """
         raise NotImplementedError()
 
-    def _get_revision_timestamp(self, revision):
-        """
-        Lazily load the revision's timestamp. If accessing it is cheap, it can
-        be given as a parameter to StoredRevision instantiation instead.
-        Return the timestamp (a long).
-
-        :type revision: Object of a subclass of Revision.
-        :param revision: The revision on which we want to operate.
-        :returns: long
-        """
-        raise NotImplementedError()
-
     def _seek_revision_data(self, revision, position, mode):
         """
         Set the revision's cursor on the revision's data.
@@ -447,8 +436,6 @@
 
     def copy_item(self, item, verbose=False, name=None):
         def same_revision(rev1, rev2):
-            if rev1.timestamp != rev2.timestamp:
-                return False
             for k, v in rev1.iteritems():
                 if rev2[k] != v:
                     return False
@@ -485,7 +472,6 @@
             else:
                 for k, v in revision.iteritems():
                     new_rev[k] = v
-                new_rev.timestamp = revision.timestamp
                 shutil.copyfileobj(revision, new_rev)
                 new_item.commit()
                 st = 'converts'
@@ -725,6 +711,8 @@
         assert rev is not None
         rev[HASH_ALGORITHM] = unicode(rev._rev_hash.hexdigest())
         rev[SIZE] = rev._size
+        if MTIME not in rev:
+            rev[MTIME] = int(time.time())
         self._backend._commit_item(rev)
         self._uncommitted_revision = None
 
@@ -779,7 +767,7 @@
     care must be taken in that case to create monotone timestamps!
     This timestamp is also retrieved via the backend's history() method.
     """
-    def __init__(self, item, revno, timestamp=None):
+    def __init__(self, item, revno):
         """
         Initialize the revision.
 
@@ -795,7 +783,6 @@
         self._item = item
         self._backend = item._backend
         self._metadata = None
-        self._timestamp = timestamp
 
     def _get_item(self):
         return self._item
@@ -811,6 +798,11 @@
     revno = property(get_revno, doc=("This property stores the revno of the revision object. "
                                      "Only read-only access is allowed."))
 
+    @property
+    def timestamp(self):
+        """This property returns the creation timestamp of the revision"""
+        return self[MTIME]
+
     def _load_metadata(self):
         self._metadata = self._backend._get_revision_metadata(self)
 
@@ -846,18 +838,11 @@
     Do NOT create instances of this class directly, but use item.get_revision or
     one of the other methods intended for getting stored revisions.
     """
-    def __init__(self, item, revno, timestamp=None):
+    def __init__(self, item, revno):
         """
         Initialize the StoredRevision
         """
-        Revision.__init__(self, item, revno, timestamp)
-
-    def _get_ts(self):
-        if self._timestamp is None:
-            self._timestamp = self._backend._get_revision_timestamp(self)
-        return self._timestamp
-
-    timestamp = property(_get_ts, doc="This property returns the creation timestamp of the revision")
+        Revision.__init__(self, item, revno)
 
     def __setitem__(self, key, value):
         """
@@ -906,22 +891,13 @@
         """
         Initialize the NewRevision
         """
-        Revision.__init__(self, item, revno, None)
+        Revision.__init__(self, item, revno)
         self._metadata = {}
         # these values need to be kept uptodate to that item.commit() can
         # use them to update the metadata of the rev before committing it:
         self._size = 0
         self._rev_hash = hashlib.new(HASH_ALGORITHM)
 
-    def _get_ts(self):
-        return self._timestamp
-
-    def _set_ts(self, ts):
-        ts = long(ts)
-        self._timestamp = ts
-
-    timestamp = property(_get_ts, _set_ts, doc="This property accesses the creation timestamp of the revision")
-
     def __setitem__(self, key, value):
         """
         Internal method used for dict-like access to the NewRevisions metadata-dict.
--- a/MoinMoin/storage/_tests/test_backends.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/_tests/test_backends.py	Sat Mar 12 23:33:46 2011 +0100
@@ -16,7 +16,7 @@
 """
 
 
-import py.test, re
+import py.test, re, time
 
 from flask import g as flaskg
 
@@ -538,13 +538,13 @@
         py.test.raises(RevisionAlreadyExistsError, item2.commit)
 
     def test_timestamp(self):
+        tnow = int(time.time())
         item = self.backend.create_item(u'ts1')
         rev = item.create_revision(0)
-        assert rev.timestamp is None
-        rev.timestamp = 42
         item.commit()
         item = self.backend.get_item(u'ts1')
-        assert item.get_revision(0).timestamp == 42
+        ts = item.get_revision(0).timestamp
+        assert tnow <= ts <= ts + 60
 
     def test_size(self):
         item = self.backend.create_item(u'size1')
--- a/MoinMoin/storage/_tests/test_backends_hg.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/_tests/test_backends_hg.py	Sat Mar 12 23:33:46 2011 +0100
@@ -82,7 +82,7 @@
         item.commit()
         item = self.backend.get_item('existing')
         rev = item.get_revision(-1)
-        assert len(dict(rev)) == 10000 + 2 # 'sha1' and 'size' key is added automatically on commit
+        assert len(dict(rev)) == 10000 + 3 # 'sha1', 'size', 'mtime' key is added automatically on commit
         for num in xrange(10000):
             revval = "revision metadata value for key %d" % num
             assert rev["%s" % num] == revval * 10
--- a/MoinMoin/storage/_tests/test_serialization.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/_tests/test_serialization.py	Sat Mar 12 23:33:46 2011 +0100
@@ -26,7 +26,7 @@
 
     def test_serialize_rev(self):
         become_trusted()
-        params = (u'foo1', 0, dict(m1=u"m1"), 'bar1')
+        params = (u'foo1', 0, dict(m1=u"m1", mtime=1234), 'bar1')
         item = update_item(*params)
         rev = item.get_revision(0)
         xmlfile = StringIO()
@@ -38,12 +38,15 @@
                     '<entry key="mimetype"><str>application/octet-stream</str>\n</entry>\n'
                     '<entry key="sha1"><str>763675d6a1d8d0a3a28deca62bb68abd8baf86f3</str>\n</entry>\n'
                     '<entry key="m1"><str>m1</str>\n</entry>\n'
+                    '<entry key="uuid"><str>foo1</str>\n</entry>\n'
                     '<entry key="name"><str>foo1</str>\n</entry>\n'
+                    '<entry key="mtime"><int>1234</int>\n</entry>\n'
                     '<entry key="size"><int>4</int>\n</entry>\n'
-                    '<entry key="uuid"><str>foo1</str>\n</entry>\n'
                     '</meta>\n'
                     '<data coding="base64"><chunk>YmFyMQ==</chunk>\n</data>\n'
                     '</revision>\n')
+        print expected
+        print xml
         assert expected == xml
 
 
@@ -52,8 +55,8 @@
     def test_serialize_item(self):
         become_trusted()
         testparams = [
-            (u'foo2', 0, dict(m1=u"m1r0"), 'bar2'),
-            (u'foo2', 1, dict(m1=u"m1r1"), 'baz2'),
+            (u'foo2', 0, dict(m1=u"m1r0", mtime=1234), 'bar2'),
+            (u'foo2', 1, dict(m1=u"m1r1", mtime=1235), 'baz2'),
         ]
         for params in testparams:
             item = update_item(*params)
@@ -68,9 +71,10 @@
                     '<entry key="mimetype"><str>application/octet-stream</str>\n</entry>\n'
                     '<entry key="sha1"><str>033c4846b506a4a48e32cdf54515c91d3499adb3</str>\n</entry>\n'
                     '<entry key="m1"><str>m1r0</str>\n</entry>\n'
+                    '<entry key="uuid"><str>foo2</str>\n</entry>\n'
                     '<entry key="name"><str>foo2</str>\n</entry>\n'
+                    '<entry key="mtime"><int>1234</int>\n</entry>\n'
                     '<entry key="size"><int>4</int>\n</entry>\n'
-                    '<entry key="uuid"><str>foo2</str>\n</entry>\n'
                     '</meta>\n'
                     '<data coding="base64"><chunk>YmFyMg==</chunk>\n</data>\n'
                     '</revision>\n'
@@ -79,13 +83,16 @@
                     '<entry key="mimetype"><str>application/octet-stream</str>\n</entry>\n'
                     '<entry key="sha1"><str>f91d8fc20a5de853e62105cc1ee0bf47fd7ded0f</str>\n</entry>\n'
                     '<entry key="m1"><str>m1r1</str>\n</entry>\n'
+                    '<entry key="uuid"><str>foo2</str>\n</entry>\n'
                     '<entry key="name"><str>foo2</str>\n</entry>\n'
+                    '<entry key="mtime"><int>1235</int>\n</entry>\n'
                     '<entry key="size"><int>4</int>\n</entry>\n'
-                    '<entry key="uuid"><str>foo2</str>\n</entry>\n'
                     '</meta>\n'
                     '<data coding="base64"><chunk>YmF6Mg==</chunk>\n</data>\n'
                     '</revision>\n'
                     '</item>\n')
+        print expected
+        print xml
         assert expected == xml
 
 class TestSerializeBackend(object):
--- a/MoinMoin/storage/backends/_flatutils.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/backends/_flatutils.py	Sat Mar 12 23:33:46 2011 +0100
@@ -5,7 +5,7 @@
     MoinMoin - helpers for flatfile meta/data stores
 """
 
-from MoinMoin.config import NAME, ACL, MIMETYPE, LANGUAGE
+from MoinMoin.config import NAME, ACL, MIMETYPE, MTIME, LANGUAGE
 
 
 def split_body(body):
@@ -58,7 +58,7 @@
     """
     Adds the processing instructions to the data.
     """
-    meta_keys = [NAME, ACL, MIMETYPE, LANGUAGE, ]
+    meta_keys = [NAME, ACL, MIMETYPE, MTIME, LANGUAGE, ]
 
     metadata_data = ""
     for key, value in metadata.iteritems():
--- a/MoinMoin/storage/backends/acl.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/backends/acl.py	Sat Mar 12 23:33:46 2011 +0100
@@ -442,14 +442,11 @@
         """
         return self._item
 
-    def _get_ts(self):
+    @property
+    def timestamp(self):
+        """This property accesses the creation timestamp of the revision"""
         return self._revision.timestamp
 
-    def _set_ts(self, ts):
-        self._revision.timestamp = ts
-
-    timestamp = property(_get_ts, _set_ts, doc="This property accesses the creation timestamp of the revision")
-
     def __setitem__(self, key, value):
         """
         In order to change an ACL on an item you must have the ADMIN privilege.
--- a/MoinMoin/storage/backends/fileserver.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/backends/fileserver.py	Sat Mar 12 23:33:46 2011 +0100
@@ -23,8 +23,7 @@
 from MoinMoin.storage import Backend, Item, StoredRevision
 from MoinMoin.storage.error import NoSuchItemError, NoSuchRevisionError
 
-from MoinMoin.config import ACL, MIMETYPE, ACTION, COMMENT, SIZE
-MTIME = '__timestamp' # does not exist in storage any more
+from MoinMoin.config import ACL, MIMETYPE, ACTION, COMMENT, MTIME, SIZE
 
 class FSError(Exception):
     """ file serving backend error """
@@ -110,9 +109,6 @@
             rev._fs_data_file = open(rev._fs_data_fname, 'rb') # XXX keeps file open as long as rev exists
         return rev._fs_data_file.seek(position, mode)
 
-    def _get_revision_timestamp(self, rev):
-        return rev._fs_meta[MTIME]
-
 
 # Specialized Items/Revisions
 
@@ -156,7 +152,7 @@
         filepath = item._fs_filepath
         st = item._fs_stat
         meta = { # make something up
-            MTIME: st.st_mtime,
+            MTIME: int(st.st_mtime),
             ACTION: 'SAVE',
             SIZE: st.st_size,
         }
--- a/MoinMoin/storage/backends/flatfile.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/backends/flatfile.py	Sat Mar 12 23:33:46 2011 +0100
@@ -33,7 +33,7 @@
                                    RevisionAlreadyExistsError
 from MoinMoin.storage.backends._fsutils import quoteWikinameFS, unquoteWikiname
 from MoinMoin.storage.backends._flatutils import add_metadata_to_body, split_body
-from MoinMoin.config import MIMETYPE, ACTION
+from MoinMoin.config import MIMETYPE, ACTION, MTIME
 
 
 class FlatFileBackend(Backend):
@@ -173,10 +173,6 @@
     def _get_item_metadata(self, item):
         return {}
 
-    def _get_revision_timestamp(self, rev):
-        revpath = self._rev_path(rev.item.name)
-        return os.stat(revpath).st_ctime
-
     def _seek_revision_data(self, rev, position, mode):
         rev._data.seek(position, mode)
 
--- a/MoinMoin/storage/backends/fs.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/backends/fs.py	Sat Mar 12 23:33:46 2011 +0100
@@ -322,8 +322,7 @@
 
     def _commit_item(self, rev):
         item = rev.item
-        metadata = {'__timestamp': rev.timestamp}
-        metadata.update(rev)
+        metadata = dict(rev)
         md = pickle.dumps(metadata, protocol=PICKLEPROTOCOL)
 
         hasdata = rev._fs_file.tell() > self._revmeta_reserved_space + 4
@@ -460,11 +459,6 @@
         f.seek(pos)
         return rev._fs_metadata
 
-    def _get_revision_timestamp(self, rev):
-        if rev._fs_metadata is None:
-            self._get_revision_metadata(rev)
-        return rev._fs_metadata['__timestamp']
-
     def _seek_revision_data(self, rev, position, mode):
         if rev._fs_file is None:
             self._get_revision_metadata(rev)
--- a/MoinMoin/storage/backends/fs19.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/backends/fs19.py	Sat Mar 12 23:33:46 2011 +0100
@@ -33,7 +33,7 @@
 
 from MoinMoin import wikiutil, config
 from MoinMoin.config import ACL, MIMETYPE, UUID, NAME, NAME_OLD, REVERTED_TO, \
-                            ACTION, ADDRESS, HOSTNAME, USERID, EXTRA, COMMENT, \
+                            ACTION, ADDRESS, HOSTNAME, USERID, MTIME, EXTRA, COMMENT, \
                             IS_SYSITEM, SYSITEM_VERSION, \
                             TAGS, SIZE, HASH_ALGORITHM
 from MoinMoin.storage import Backend, Item, StoredRevision
@@ -41,8 +41,6 @@
 from MoinMoin.storage.backends._flatutils import split_body
 
 
-MTIME = '__timestamp' # does not exist in storage any more
-
 from MoinMoin.storage.error import NoSuchItemError, NoSuchRevisionError
 
 DELETED_MODE_KEEP = 'keep'
@@ -268,9 +266,6 @@
             rev._fs_data_file = open(rev._fs_data_fname, 'rb') # XXX keeps file open as long as rev exists
         return rev._fs_data_file.seek(position, mode)
 
-    def _get_revision_timestamp(self, rev):
-        return rev._fs_meta[MTIME]
-
 
 # Specialized Items/Revisions
 
@@ -367,7 +362,7 @@
                 if 0 <= revno <= item._fs_current:
                     editlog_data = { # make something up
                         NAME: item.name,
-                        MTIME: os.path.getmtime(revpath),
+                        MTIME: int(os.path.getmtime(revpath)),
                         ACTION: u'SAVE',
                     }
             meta, data = split_body(content)
@@ -478,7 +473,7 @@
             editlog_data = editlog.find_attach(item._fs_attachname)
         except KeyError:
             editlog_data = { # make something up
-                MTIME: os.path.getmtime(attpath),
+                MTIME: int(os.path.getmtime(attpath)),
                 ACTION: u'SAVE',
             }
         meta = editlog_data
--- a/MoinMoin/storage/backends/fs2.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/backends/fs2.py	Sat Mar 12 23:33:46 2011 +0100
@@ -313,8 +313,7 @@
 
     def _commit_item(self, rev):
         item = rev.item
-        metadata = {'__timestamp': rev.timestamp}
-        metadata.update(rev)
+        metadata = dict(rev)
         md = pickle.dumps(metadata, protocol=PICKLEPROTOCOL)
 
         rev._fs_file_meta.write(md)
@@ -417,9 +416,6 @@
     def _get_revision_metadata(self, rev):
         return rev._fs_metadata
 
-    def _get_revision_timestamp(self, rev):
-        return rev._fs_metadata['__timestamp']
-
     def _open_revision_data(self, rev, mode='rb'):
         if rev._fs_file_data is None:
             rev._fs_file_data = open(rev._fs_path_data, mode) # XXX keeps file open as long as rev exists
--- a/MoinMoin/storage/backends/hg.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/backends/hg.py	Sat Mar 12 23:33:46 2011 +0100
@@ -56,7 +56,7 @@
 except ImportError:
     from MoinMoin.util import pycdb as cdb
 
-from MoinMoin.config import USERID, COMMENT
+from MoinMoin.config import USERID, COMMENT, MTIME
 from MoinMoin.storage import Backend, Item, StoredRevision, NewRevision
 from MoinMoin.storage.error import (BackendError, NoSuchItemError, NoSuchRevisionError,
                                    RevisionNumberMismatchError, ItemAlreadyExistsError,
@@ -165,7 +165,7 @@
         def restore_revision(name, id):
             item = Item(self, name)
             item._id = id
-            rev = MercurialStoredRevision(item, revno, timestamp)
+            rev = MercurialStoredRevision(item, revno)
             rev._item_id = item._id
             return rev
 
@@ -179,7 +179,7 @@
 
         for ctx in self._iter_changelog(reverse=reverse):
             meta = self._decode_metadata(ctx.extra(), BACKEND_METADATA_PREFIX)
-            revno, oldid, oldname, timestamp = meta['rev'], meta['id'], meta['name'], long(ctx.date()[0])
+            revno, oldid, oldname = meta['rev'], meta['id'], meta['name']
             try:
                 for (id, name) in renamed_items[oldid]:
                     # consider you have backend merged from two instances,
@@ -309,8 +309,8 @@
         # If there hasn't been a timestamp already assigned, assign one.
         # Note: this is done here primarily to avoid test breakage, the production
         #       timestamps are generated by indexing, see update_index()
-        if not revision.timestamp:
-            revision.timestamp = long(time.time())
+        if MTIME not in revision:
+            revision[MTIME] = int(time.time())
         item = revision.item
         lock = self._lock_rev_item(item)
         try:
@@ -335,7 +335,7 @@
             meta = self._encode_metadata(internal_meta, BACKEND_METADATA_PREFIX)
             meta.update(self._encode_metadata(revision, WIKI_METADATA_PREFIX))
 
-            date = datetime.fromtimestamp(revision.timestamp).isoformat(sep=' ')
+            date = datetime.fromtimestamp(revision[MTIME]).isoformat(sep=' ')
             user = revision.get(USERID, DEFAULT_USER).encode("utf-8")
             msg = revision.get(COMMENT, DEFAULT_COMMIT_MESSAGE).encode("utf-8")
 
@@ -431,10 +431,6 @@
         extra = self._get_changectx(revision).extra()
         return self._decode_metadata(extra, WIKI_METADATA_PREFIX)
 
-    def _get_revision_timestamp(self, revision):
-        """Return given Revision timestamp"""
-        return long(self._get_filectx(revision).date()[0])
-
     def _seek_revision_data(self, revision, position, mode):
         """Set the Revisions cursor on the Revisions data."""
         self._open_revision_data(revision)
@@ -648,8 +644,8 @@
 
 class MercurialStoredRevision(StoredRevision):
 
-    def __init__(self, item, revno, timestamp=None):
-        StoredRevision.__init__(self, item, revno, timestamp)
+    def __init__(self, item, revno):
+        StoredRevision.__init__(self, item, revno)
         self._data = None
 
     def get_parents(self):
--- a/MoinMoin/storage/backends/indexing.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/backends/indexing.py	Sat Mar 12 23:33:46 2011 +0100
@@ -26,7 +26,7 @@
 logging = log.getLogger(__name__)
 
 from MoinMoin.storage.error import NoSuchItemError, NoSuchRevisionError
-from MoinMoin.config import ACL, MIMETYPE, UUID, NAME, NAME_OLD, TAGS
+from MoinMoin.config import ACL, MIMETYPE, UUID, NAME, NAME_OLD, MTIME, TAGS
 
 
 class IndexingBackendMixin(object):
@@ -149,8 +149,8 @@
         name = self.item.name
         uuid = name # XXX
         revno = self.revno
-        if self.timestamp is None:
-            self.timestamp = time.time()
+        if MTIME not in self:
+            self[MTIME] = int(time.time())
         if NAME not in self:
             self[NAME] = name
         if UUID not in self:
@@ -161,7 +161,7 @@
         logging.debug("item %r revno %d update index:" % (name, revno))
         for k, v in metas.items():
             logging.debug(" * rev meta %r: %r" % (k, v))
-        self._index.add_rev(uuid, revno, self.timestamp, metas)
+        self._index.add_rev(uuid, revno, metas)
 
     def remove_index(self):
         """
@@ -293,7 +293,7 @@
             self.item_kvstore.store_kv(item_id, {})
             item_table.delete().where(item_table.c.id == item_id).execute()
 
-    def add_rev(self, uuid, revno, timestamp, metas):
+    def add_rev(self, uuid, revno, metas):
         """
         add a new revision <revno> for item <uuid> with metadata <metas>
 
@@ -311,7 +311,7 @@
         if result:
             rev_id = result[0]
         else:
-            dt = datetime.datetime.utcfromtimestamp(timestamp)
+            dt = datetime.datetime.utcfromtimestamp(metas[MTIME])
             res = rev_table.insert().values(revno=revno, item_id=item_id, datetime=dt).execute()
             rev_id = res.inserted_primary_key[0]
 
--- a/MoinMoin/storage/backends/memory.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/backends/memory.py	Sat Mar 12 23:33:46 2011 +0100
@@ -166,7 +166,7 @@
         except KeyError:
             raise NoSuchRevisionError("No Revision #%d on Item %s - Available revisions: %r" % (revno, item.name, revisions))
         else:
-            revision = self.StoredRevision(item, revno, timestamp=metadata['__timestamp'])
+            revision = self.StoredRevision(item, revno)
             revision._data = StringIO.StringIO(data)
             revision._metadata = metadata
             return revision
@@ -270,7 +270,6 @@
 
         if revision._metadata is None:
             revision._metadata = {}
-        revision._metadata['__timestamp'] = revision.timestamp
         self._item_revisions[item._item_id][revision.revno] = (revision._data.getvalue(), revision._metadata.copy())
         revision = item.get_revision(revision.revno)
         self._revision_history.append(revision)
--- a/MoinMoin/storage/backends/router.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/backends/router.py	Sat Mar 12 23:33:46 2011 +0100
@@ -339,14 +339,10 @@
     def revno(self):
         return self._revision.revno
 
-    def _get_ts(self):
+    @property
+    def timestamp(self):
         return self._revision.timestamp
 
-    def _set_ts(self, ts):
-        self._revision.timestamp = ts
-
-    timestamp = property(_get_ts, _set_ts, doc="This property accesses the creation timestamp of the revision")
-
     def __setitem__(self, key, value):
         """
         We only need to redirect this manually here because python doesn't do that
--- a/MoinMoin/storage/backends/sqla.py	Sat Mar 12 16:31:43 2011 +0100
+++ b/MoinMoin/storage/backends/sqla.py	Sat Mar 12 23:33:46 2011 +0100
@@ -589,12 +589,10 @@
     _item = relation(SQLAItem, backref=backref('_revisions', cascade='delete, delete-orphan', lazy=True), cascade='', uselist=False, lazy=False)
     _revno = Column(Integer, index=True)
     _metadata = Column(PickleType)
-    _timestamp = Column(Integer)
 
     def __init__(self, item, revno, *args, **kw):
         super(SQLARevision, self).__init__(item, revno, *args, **kw)
         self._revno = revno
-        self._timestamp = kw.get('timestamp')
         self.setup(item._backend)
         self._item = item