thanks Iceberg.

your approach is pretty much what I have right now. I'm looking for a
bullet-proof approach.
otherwise I'm running code with "fingers crossed two users don't use
the system at the same time"

and I want to encourage usage :)

C





On May 27, 6:09 pm, Iceberg <iceb...@21cn.com> wrote:
> On May27, 11:32pm, Carl <carl.ro...@gmail.com> wrote:
>
>
>
>
>
> > the flaw is in my architecture not web2py. can you help with a better
> > approach? Needs to be BigTable-friendly to boot.
>
> > I have two user types: Agents and Candidates
> > Agents invite Candidates to Parties.
>
> > I keep a Party table recording all such Party invites.
> > Candidates can be invited to the same Party by several Agents so I
> > have an Invite table recording which Agents invited which Candidates
> > to which Parties.
>
> > 1. On a new Party invitation I check if the Candidate has already been
> > invited by looking in the Party table.
> > 2. If a party isn't found then I insert into the Party table
> > 3. I insert the Agent into Invite table has a value pointing to the
> > appropriate Party row.
>
> > Here's the "race condition"...
>
> > **Between** steps 1 and 2 above another party invite is sent and
> > checked for pre-existance. it's not found because step 2 by the 1st
> > agent's run through hasn't yet executed.
>
> > Thus duplicate party invitations are inserted into the database.
>
> > What's the better approach to employ?
>
> Here is my attempt. Not a perfect one.
>
> db.define_table('Agent', Field('name', unique=True))
> db.define_table('Candidate', Field('name', unique=True))
> db.define_table('Party', Field('name', unique=True))
> db.define_table('Invitation',
>   Field('agent', db.Agent),
>   Field('candidate', db.Candidate),
>   Field('party', db.Party),
>   # Ideally, we should set up two fields, candidate and party,
>   # as combinated primary key in db level. But I don't know how.
>   )
>
> # Then, in controller
> def invite():
>   def no_duplicate(form):
>     if db( (db.Invitation.candidate==form.vars.candidate)
>          & (db.Invitation.party==form.vars.party) ).count():
>         form.errors.candidate = 'Already invited to this party'
>   form = SQLFORM(db.Invitation)
>   if form.accepts( ..., onvalidation=no_duplicate):
>     response.flash = 'ok'
>     # However, theoretically speaking there is still a slim time gap,
>     # maybe 0.2 second, between the onvalidation and the later
> insertion.
>   return {'':form}

Reply via email to