Skip to content
This repository has been archived by the owner on Mar 1, 2022. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
Added collision-free sequence generation in place of transaction that…
… timed out too frequently. Bug 660876.
  • Loading branch information
Fred Wenzel committed May 31, 2011
1 parent 0c4f417 commit 6ca2e83
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 5 deletions.
35 changes: 31 additions & 4 deletions ffdemo/markup/common.py
Expand Up @@ -3,7 +3,7 @@
import re
import bcrypt

from django.db import transaction
from django.db import connection

from ffdemo.markup.models import Mark
from ffdemo.markup.models import Invitation
Expand Down Expand Up @@ -43,6 +43,8 @@ def pack_mark_objects(data):


def save_new_mark_with_data(data, ip_address):
"""Preprocess mark data, then save to DB."""

# Remove whitespace from raw full points obj
stripped_points_obj_full = re.sub(r'\s', '', data['points_obj'])
# remove whitespace where not in extra_info (the contributor quote)
Expand Down Expand Up @@ -78,14 +80,17 @@ def save_new_mark_with_data(data, ip_address):
f.write(stripped_points_obj_full)
return reference

@transaction.commit_on_success

def create_save_mark(duplicate_hash, obscurred_ip, stripped_points_obj_simplified, data):
new_mark = Mark.objects.create()
reference = short_url.encode_url(new_mark.id)
"""Save mark to database."""

new_mark = Mark()
reference = generate_reference()
new_mark.duplicate_check = duplicate_hash
new_mark.ip_address = obscurred_ip
new_mark.points_obj_simplified = stripped_points_obj_simplified
new_mark.reference = reference

invite = None
if 'country_code' in data:
new_mark.country_code = data['country_code']
Expand All @@ -97,8 +102,30 @@ def create_save_mark(duplicate_hash, obscurred_ip, stripped_points_obj_simplifie
new_mark.contributor = data['contributor']

new_mark.save()

if invite:
invite.used_at = datetime.now()
invite.save()

return new_mark.reference


def generate_reference():
"""Generates a new, unique reference string for a mark."""

# This is some raw SQL to keep things atomic. Straight from the MySQL docs:
# http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id
cursor = connection.cursor()
cursor.execute("""UPDATE markup_marksequence SET
id=LAST_INSERT_ID(id + 1)""")

# The sequence table should never be empty. But alas, if it is, let's
# fix it.
if not cursor.rowcount > 0:
cursor.execute("""INSERT INTO markup_marksequence (id)
VALUES(LAST_INSERT_ID(id + 1))""")

cursor.execute('SELECT LAST_INSERT_ID() FROM markup_marksequence')
id = cursor.fetchone()[0]

return short_url.encode_url(id)
55 changes: 55 additions & 0 deletions ffdemo/markup/migrations/0019_add_model_MarkSequence.py
@@ -0,0 +1,55 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models

class Migration(SchemaMigration):

def forwards(self, orm):

# Adding model 'MarkSequence'
db.create_table('markup_marksequence', (
('id', self.gf('django.db.models.fields.IntegerField')(primary_key=True)),
))
db.send_create_signal('markup', ['MarkSequence'])

# Initialize mark sequence ID from existing data.
db.execute("INSERT INTO markup_marksequence SET id = (SELECT MAX(id) FROM markup_mark)")


def backwards(self, orm):

# Deleting model 'MarkSequence'
db.delete_table('markup_marksequence')


models = {
'markup.invitation': {
'Meta': {'object_name': 'Invitation'},
'contributor_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'invite_code': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'}),
'used_at': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'})
},
'markup.mark': {
'Meta': {'object_name': 'Mark'},
'contributor': ('django.db.models.fields.CharField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
'contributor_locale': ('django.db.models.fields.CharField', [], {'max_length': '5', 'null': 'True', 'blank': 'True'}),
'country_code': ('django.db.models.fields.CharField', [], {'max_length': '2', 'blank': 'True'}),
'date_drawn': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
'duplicate_check': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
'flaggings': ('django.db.models.fields.IntegerField', [], {'default': '0', 'db_index': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ip_address': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'points_obj_simplified': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'reference': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'unique': 'True', 'max_length': '50', 'blank': 'True'})
},
'markup.marksequence': {
'Meta': {'object_name': 'MarkSequence'},
'id': ('django.db.models.fields.IntegerField', [], {'primary_key': 'True'})
}
}

complete_apps = ['markup']
9 changes: 8 additions & 1 deletion ffdemo/markup/models.py
Expand Up @@ -11,7 +11,7 @@ class Mark(models.Model):
date_drawn = models.DateTimeField(auto_now_add=True, db_index=True)
reference = models.CharField(max_length=50, blank=True, db_index=True, unique=True)
points_obj_simplified = models.TextField(blank=True)
country_code = models.CharField(max_length=2, blank=True)
country_code = models.CharField(max_length=2, blank=True, db_index=True)
flaggings = models.IntegerField(default=0, db_index=True)
is_approved = models.BooleanField(default=False)
# contributor attrs
Expand All @@ -24,6 +24,13 @@ def __unicode__(self):
return unicode(self.date_drawn)


class MarkSequence(models.Model):
"""
The mark sequence table, spitting out unique IDs to be used as references.
"""
id = models.IntegerField(primary_key=True)


class Invitation(models.Model):
invite_code = models.SlugField(max_length=50, unique=True, db_index=True)
contributor_type = models.CharField(max_length=1, choices=settings.CONTRIBUTOR_TYPE_CHOICES)
Expand Down

0 comments on commit 6ca2e83

Please sign in to comment.