[Dbix-class] Race condition in find_or_create()
Ash Berlin
ash_cpan at firemirror.com
Wed Jul 30 16:01:24 BST 2008
On 30 Jul 2008, at 15:44, Tobias Kremer wrote:
> As many of you probably know, the current find_or_create()
> implementation contains a race-condition.
> Catalyst::Plugin::Session::Store::DBIC is especially prone to die in
> front of the user when using the flash() method - even more so when
> AJAX calls are involved resulting in two or more concurrent requests
> trying to select/insert the flash data into the database via
> find_or_create().
>
> I proposed the following reverse order implementation on the
> Catalyst mailing list which will hopefully not only reduce the
> probability of a race-condition but will also reduce
> find_or_create() to a single query in the best case.
>
> On Tue, Jul 29, 2008 at 12:49:17PM +0200, Tobias Kremer wrote:
>> Maybe it'd be better to ditch find_or_create in favor of something
>> like this:
>> eval {
>> $row = $self->model->create( { ... } );
>> }
>> if( $@ && $@ =~ /duplicate/ ) { # the question about detecting this
>> remains
>> $row = $self->model->find( { ... } );
>> }
>> This would reduce the query to 1 at best and 2 at worst.
>
>
> mst responded with:
>
> On 30.07.2008, at 12:26, Matt S Trout wrote:
>> It's still probably viable.
>> What I'd really like is to add some code to DBIC's storage to know
>> what re
>> that /duplicate/ is on whatever DB so we can bury this away from
>> the user
>> and DBIC can Just Use It for find_or_create on any supported
>> database.
>> Maybe you could wander over to the DBIC list and poke at patching
>> that
>> instead?
>
> So, the problem is: How to detect if the insert failed due to a
> unique key constraint for all supported databases?
>
> I'd volunteer to help implementing this but as of now I'm not that
> deep into DBIC to know exactly how to pull this off. So I'd really
> appreciate a few ideas and thoughts.
>
> I suppose we could put a method returning a database-dependent
> regular expression that detects unique key constraint errors into
> the DBIx::Class::Storage::DBI::* classes and use that from within
> find_or_create().
>
> What do you think?
>
> --Tobias
>
Yes but not quite like that.
A method on the storage object (which is subclassed to be the
particular type of DBI you are connecting to, eg
DBIx::Class::Storage::DBI::mysql) which parses and encapsulates the
error as returned from the database to mark its type, e.g. FK
constraint violation, duplicate key, etc. etc.
Then you could check $@->type eq 'duplicate_key' or something.
Comments?
More information about the DBIx-Class
mailing list