You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by je...@apache.org on 2014/10/17 16:59:18 UTC

[1/3] git commit: [#7647] ticket:669 Add test to reproduce race condition in artifact versioning

Repository: allura
Updated Branches:
  refs/heads/je/7647 [created] e249a8fcd


[#7647] ticket:669 Add test to reproduce race condition in artifact versioning


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/b2270346
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/b2270346
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/b2270346

Branch: refs/heads/je/7647
Commit: b22703461770d3d662c961e183f2f8dc184e756f
Parents: 10472d1
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Oct 17 16:05:18 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Fri Oct 17 16:45:43 2014 +0300

----------------------------------------------------------------------
 ForgeWiki/forgewiki/tests/test_models.py | 59 +++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/b2270346/ForgeWiki/forgewiki/tests/test_models.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/tests/test_models.py b/ForgeWiki/forgewiki/tests/test_models.py
new file mode 100644
index 0000000..619f5dd
--- /dev/null
+++ b/ForgeWiki/forgewiki/tests/test_models.py
@@ -0,0 +1,59 @@
+#       Licensed to the Apache Software Foundation (ASF) under one
+#       or more contributor license agreements.  See the NOTICE file
+#       distributed with this work for additional information
+#       regarding copyright ownership.  The ASF licenses this file
+#       to you under the Apache License, Version 2.0 (the
+#       "License"); you may not use this file except in compliance
+#       with the License.  You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#       Unless required by applicable law or agreed to in writing,
+#       software distributed under the License is distributed on an
+#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#       KIND, either express or implied.  See the License for the
+#       specific language governing permissions and limitations
+#       under the License.
+
+from allura.tests import TestController
+from allura.tests import decorators as td
+from alluratest.controller import setup_global_objects
+
+from forgewiki.model import Page
+
+
+class TestPageSnapshots(TestController):
+
+    # Note: test name starts with '_' makes nose don't pick it up automatically.
+    # This is done intentionally to avoid run this test on every commit.
+    # You can run it manually like this:
+    # nosetests forgewiki.tests.test_models:TestPageSnapshots._test_version_race
+    # You should check that threads does not throw `DuplicateKeyError`.
+    # It's hard to reproduce this mannually
+    @td.with_wiki
+    def _test_version_race(self):
+        import time
+        import random
+        from threading import Thread
+
+        page = Page.upsert('test-page')
+        page.commit()
+
+        def run(n):
+            setup_global_objects()
+            for i in range(10):
+                page = Page.query.get(title='test-page')
+                page.text = 'Test Page %s.%s' % (n, i)
+                time.sleep(random.random())
+                page.commit()
+
+        t1 = Thread(target=lambda: run(1))
+        t2 = Thread(target=lambda: run(2))
+        t1.start()
+        t2.start()
+        t1.join()
+        t2.join()
+
+        page = Page.query.get(title='test-page')
+        # 10 changes by each thread + initial upsert
+        assert page.history().count() == 21, page.history().count()


[3/3] git commit: [#7647] ticket:669 Let test be discovered by nose

Posted by je...@apache.org.
[#7647] ticket:669 Let test be discovered by nose


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/e249a8fc
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/e249a8fc
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/e249a8fc

Branch: refs/heads/je/7647
Commit: e249a8fcdc8a354462909bf8a3e7c601ddcc9ac6
Parents: 420e169
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Oct 17 16:58:44 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Fri Oct 17 16:58:44 2014 +0300

----------------------------------------------------------------------
 ForgeWiki/forgewiki/tests/test_models.py | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/e249a8fc/ForgeWiki/forgewiki/tests/test_models.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/tests/test_models.py b/ForgeWiki/forgewiki/tests/test_models.py
index 619f5dd..ac07669 100644
--- a/ForgeWiki/forgewiki/tests/test_models.py
+++ b/ForgeWiki/forgewiki/tests/test_models.py
@@ -24,14 +24,10 @@ from forgewiki.model import Page
 
 class TestPageSnapshots(TestController):
 
-    # Note: test name starts with '_' makes nose don't pick it up automatically.
-    # This is done intentionally to avoid run this test on every commit.
-    # You can run it manually like this:
-    # nosetests forgewiki.tests.test_models:TestPageSnapshots._test_version_race
-    # You should check that threads does not throw `DuplicateKeyError`.
-    # It's hard to reproduce this mannually
     @td.with_wiki
-    def _test_version_race(self):
+    def test_version_race(self):
+        # threads must not throw DuplicateKeyError
+        # details https://sourceforge.net/p/allura/tickets/7647/
         import time
         import random
         from threading import Thread


[2/3] git commit: [#7647] ticket:669 Fix race condition in artifact versioning

Posted by je...@apache.org.
[#7647] ticket:669 Fix race condition in artifact versioning


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/420e1694
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/420e1694
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/420e1694

Branch: refs/heads/je/7647
Commit: 420e16941e4d03d5dfbad384eb1a23280cd8aea0
Parents: b227034
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Oct 17 16:49:27 2014 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Fri Oct 17 16:49:27 2014 +0300

----------------------------------------------------------------------
 Allura/allura/model/artifact.py | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/420e1694/Allura/allura/model/artifact.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/artifact.py b/Allura/allura/model/artifact.py
index ccb6b42..4632301 100644
--- a/Allura/allura/model/artifact.py
+++ b/Allura/allura/model/artifact.py
@@ -471,7 +471,6 @@ class VersionedArtifact(Artifact):
 
     def commit(self, update_stats=True):
         '''Save off a snapshot of the artifact and increment the version #'''
-        self.version += 1
         try:
             ip_address = request.headers.get(
                 'X_FORWARDED_FOR', request.remote_addr)
@@ -483,18 +482,28 @@ class VersionedArtifact(Artifact):
             artifact_class='%s.%s' % (
                 self.__class__.__module__,
                 self.__class__.__name__),
-            version=self.version,
             author=dict(
                 id=c.user._id,
                 username=c.user.username,
                 display_name=c.user.get_pref('display_name'),
                 logged_ip=ip_address),
-            timestamp=datetime.utcnow(),
             data=state(self).clone())
-        ss = self.__mongometa__.history_class(**data)
-        session(ss).insert_now(ss, state(ss))
+        while True:
+            self.version += 1
+            data['version'] = self.version
+            data['timestamp'] = datetime.utcnow()
+            ss = self.__mongometa__.history_class(**data)
+            try:
+                session(ss).insert_now(ss, state(ss))
+            except pymongo.errors.DuplicateKeyError:
+                log.warning('Trying to create duplicate version %s of %s',
+                            self.version, self.__class__)
+                session(ss).expunge(ss)
+                continue
+            else:
+                break
         log.debug('Snapshot version %s of %s',
-                 self.version, self.__class__)
+                  self.version, self.__class__)
         if update_stats:
             if self.version > 1:
                 g.statsUpdater.modifiedArtifact(