From 965360653ee505c76a89228bac462ada597dad0b Mon Sep 17 00:00:00 2001
From: Luke Macken <lmacken@redhat.com>
Date: Sat, 22 Nov 2008 18:27:40 -0500
Subject: [PATCH] Righteous hack for the 10k bug.

Due to a flaw in the way the PackageUpdate.assign_id method finds the update
with the highest id, when we reached 10,000 updates this year, it started to
fail.  The previous method ordered updates by the updateid string column, which
now fails since u'FEDORA-2008-10000' < u'FEDORA-2008-9999'.

This patch changes this query to grab the most recent update based on the
date_pushed column.  This technically should also have the highest updateid.
However, since SQLObject completely ignores milliseconds, we need to also
take into account multiple updates being pushed during the same second.

This changeset also includes a testcase for the 10k bug.

diff --git a/bodhi/model.py b/bodhi/model.py
index 2bc7c07..7d4627b 100644
--- a/bodhi/model.py
+++ b/bodhi/model.py
@@ -258,19 +258,37 @@ class PackageUpdate(SQLObject):
         if self.updateid != None and self.updateid != u'None':
             log.debug("Keeping current update id %s" % self.updateid)
             return
-        update = PackageUpdate.select(PackageUpdate.q.updateid != 'None',
-                                      orderBy=PackageUpdate.q.updateid)
+
+        updates = PackageUpdate.select(
+                    AND(PackageUpdate.q.date_pushed != None,
+                        PackageUpdate.q.updateid != None),
+                    orderBy=PackageUpdate.q.date_pushed, limit=1).reversed()
+
         try:
-            prefix, year, id = update[-1].updateid.split('-')
+            update = updates[0]
+
+            # We need to check if there are any other updates that were pushed
+            # at the same time, since SQLObject ignores milliseconds
+            others = PackageUpdate.select(
+                        PackageUpdate.q.date_pushed == update.date_pushed)
+            if others.count() > 1:
+                # find the update with the highest id
+                for other in others:
+                    if other.updateid_int > update.updateid_int:
+                        update = other
+
+            prefix, year, id = update.updateid.split('-')
             if int(year) != time.localtime()[0]: # new year
                 id = 0
             id = int(id) + 1
-        except (AttributeError, IndexError):
-            id = 1
+        except IndexError:
+            id = 1 # First update
+
         self.updateid = u'%s-%s-%0.4d' % (self.release.id_prefix,
                                           time.localtime()[0],id)
         log.debug("Setting updateid for %s to %s" % (self.title,
                                                      self.updateid))
+        self.date_pushed = datetime.utcnow()
         hub.commit()
 
     def set_request(self, action, pathcheck=True):
@@ -356,7 +374,6 @@ class PackageUpdate(SQLObject):
         """
         if self.request == 'testing':
             self.pushed = True
-            self.date_pushed = datetime.utcnow()
             self.status = 'testing'
             self.assign_id()
         elif self.request == 'obsolete':
@@ -364,7 +381,6 @@ class PackageUpdate(SQLObject):
             self.status = 'obsolete'
         elif self.request == 'stable':
             self.pushed = True
-            self.date_pushed = datetime.utcnow()
             self.status = 'stable'
             self.assign_id()
         self.request = None
@@ -742,6 +758,15 @@ class PackageUpdate(SQLObject):
         sorted.sort(lambda x, y: cmp(x.timestamp, y.timestamp))
         return sorted
 
+    @property
+    def updateid_int(self):
+        """ Return the integer $ID from the 'FEDORA-2008-$ID' updateid """
+        if not self.updateid:
+            return None
+        prefix, year, id = self.updateid.split('-')
+        print "returning %d for %s" % (int(id), self.updateid)
+        return int(id)
+
 
 class Comment(SQLObject):
     timestamp   = DateTimeCol(default=datetime.utcnow)
diff --git a/bodhi/tests/test_model.py b/bodhi/tests/test_model.py
index b654fe8..eab511e 100644
--- a/bodhi/tests/test_model.py
+++ b/bodhi/tests/test_model.py
@@ -109,11 +109,32 @@ class TestPackageUpdate(testutil.DBTest):
         update.assign_id()
         assert update.updateid == '%s-%s-0001' % (update.release.id_prefix,
                                                   time.localtime()[0])
+        assert update.date_pushed
         update = self.get_update(name='TurboGears-0.4.4-8.fc7')
         update.assign_id()
         assert update.updateid == '%s-%s-0002' % (update.release.id_prefix,
                                                   time.localtime()[0])
 
+        # 10k bug
+        update.updateid = 'FEDORA-2008-9999'
+        newupdate = self.get_update(name='nethack-2.5.6-1.fc10')
+        newupdate.assign_id()
+        assert newupdate.updateid == 'FEDORA-2008-10000'
+
+        newerupdate = self.get_update(name='nethack-2.5.7-1.fc10')
+        newerupdate.assign_id()
+        assert newerupdate.updateid == 'FEDORA-2008-10001'
+
+        # test updates that were pushed at the same time.  assign_id should
+        # be able to figure out which one has the highest id.
+        now = datetime.utcnow()
+        newupdate.date_pushed = now
+        newerupdate.date_pushed = now
+
+        newest = self.get_update(name='nethack-2.5.8-1.fc10')
+        newest.assign_id()
+        assert newest.updateid == 'FEDORA-2008-10002'
+
     def test_url(self):
         update = self.get_update()
         print "URL = ", update.get_url()
-- 
1.6.0.3

