[Catalyst] Session duplicate key constraints on concurrent requests

Janne Snabb snabb at epipe.com
Fri Oct 7 18:17:50 GMT 2011


On Fri, 7 Oct 2011, Janne Snabb wrote:

> I think the proper way to solve it is to drop the constraint on the
> cookie and just insert the cookie and have an auto_increment ID in
> the table. And when reading, select the cookie with the highest ID
> (because there might be several).

Something like this perhaps? Untested code.

--
Janne Snabb / EPIPE Communications
snabb at epipe.com - http://epipe.com/

diff -U5 -r Catalyst-Plugin-Session-Store-DBI-0.16/lib/Catalyst/Plugin/Session/Store/DBI.pm Catalyst-Plugin-Session-Store-DBI-0.16+sessionpatch//lib/Catalyst/Plugin/Session/Store/DBI.pm
--- Catalyst-Plugin-Session-Store-DBI-0.16/lib/Catalyst/Plugin/Session/Store/DBI.pm	2010-03-24 04:47:13.000000000 +0700
+++ Catalyst-Plugin-Session-Store-DBI-0.16+sessionpatch//lib/Catalyst/Plugin/Session/Store/DBI.pm	2011-10-08 01:13:30.183410460 +0700
@@ -120,10 +120,14 @@
 
 sub session_store_dbi_id_field {
     return shift->_session_plugin_config->{'dbi_id_field'} || 'id';
 }
 
+sub session_store_dbi_selector_field {
+    return shift->_session_plugin_config->{'dbi_selector_field'} || 'selector';
+}
+
 sub session_store_dbi_data_field {
     return shift->_session_plugin_config->{'dbi_data_field'} || 'session_data';
 }
 
 sub session_store_dbi_expires_field {
@@ -148,11 +152,11 @@
     my ( $table, $id_field, $data_field, $expires_field ) =
         map { $c->${\"session_store_$_"} }
             qw/dbi_table dbi_id_field dbi_data_field dbi_expires_field/;
     $c->_session_sql( {
         get_session_data        =>
-            "SELECT $data_field FROM $table WHERE $id_field = ?",
+            "SELECT $data_field FROM $table WHERE $id_field = ? ORDER BY selector ASC LIMIT 1",
         get_expires             =>
             "SELECT $expires_field FROM $table WHERE $id_field = ?",
         check_existing          =>
             "SELECT 1 FROM $table WHERE $id_field = ?",
         update_session          =>
@@ -338,11 +342,12 @@
 
 =head1 SYNOPSIS
 
     # Create a table in your database for sessions
     CREATE TABLE sessions (
-        id           char(72) primary key,
+        id           char(72) key,
+        selector     int auto_increment primary key,
         session_data text,
         expires      int(10)
     );
 
     # In your app
@@ -354,20 +359,22 @@
         dbi_dsn   => 'dbi:mysql:database',
         dbi_user  => 'foo',
         dbi_pass  => 'bar',
         dbi_table => 'sessions',
         dbi_id_field => 'id',
+        dbi_selector_field => 'selector',
         dbi_data_field => 'session_data',
         dbi_expires_field => 'expires',
     });
     
     # Or use an existing database handle from a DBIC/CDBI class
     MyApp->config('Plugin::Session' => {
         expires   => 3600,
         dbi_dbh   => 'DBIC', # which means MyApp::Model::DBIC
         dbi_table => 'sessions',
         dbi_id_field => 'id',
+        dbi_selector_field => 'selector',
         dbi_data_field => 'session_data',
         dbi_expires_field => 'expires',
     });
 
     # ... in an action:
@@ -423,10 +430,17 @@
 =head2 dbi_id_field
 
 The name of the field on your sessions table which stores the session ID.
 Defaults to C<id>.
 
+=head2 dbi_selector_field
+
+The name of the field on your sessions table which is used to differentiate
+amongst multiple instances of the id field (which happens when multiple
+instances try to store the same session at the same time).
+Defaults to C<selector>.
+
 =head2 dbi_data_field
 
 The name of the field on your sessions table which stores session data.
 Defaults to C<session_data>.
 
@@ -435,13 +449,14 @@
 The name of the field on your sessions table which stores the expiration
 time of the session. Defaults to C<expires>.
 
 =head1 SCHEMA
 
-Your 'sessions' table must contain at minimum the following 3 columns:
+Your 'sessions' table must contain at minimum the following 4 columns:
 
-    id           char(72) primary key
+    id           char(72) key
+    selector     int auto_increment primary key
     session_data text
     expires      int(10)
 
 The 'id' column should probably be 72 characters. It needs to handle the
 longest string that can be returned by



More information about the Catalyst mailing list