PHWinfo banniere

Titres
PORTAIL ANNUAIRE ARTICLES COMPARATEUR HÉBERGEURS DEVIS FORUMS RÉDUCTEUR D'URL
Précédent   PHWinfo > Autres forums > Forum Programmation & Conception > comp.lang.php > Managing concurrency due to multiple submits
S'inscrire FAQ Membres Recherche Messages du jour Marquer les forums comme lus
Managing concurrency due to multiple submits

Réponse
 
LinkBack Outils de la discussion
Vieux 01/03/2008, 19h52   #26
Jerry Stuckle
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Managing concurrency due to multiple submits

Jeremy@thebunnyshed.co.uk wrote:
> On Mar 1, 4:03 pm, Jerry Stuckle <jstuck...@attglobal.net> wrote:
>
>>> I totally agree with all of this, but I did not state transactional
>>> programs were like multithreaded programs. I stated that the problems
>>> of multiple instances of scripts were comparible to the problems of
>>> multithreading.

>> Not at all. Multithreaded programs have a whole different set of problems.

>
> So I will ask again, how so? Concurrency problems boil down to
> serialising access to data and intra process communication. In PHP it
> appears the session will handle both of these requirements.
>


So I will say again. You have no real communications between scripts,
other than what you pass it. And don't count on the session to be a
method for serializing access. It works that way for now, with the
default file handler. But there is no guarantee it will remain that
way, nor that it will serialize access if you're using other handlers.

>>> My point precisely. I don't want to slow it down any further than
>>> necessary.

>> Which brings me back to the point - you are prematurely optimizing. If
>> you have a problem, locate the source of that problem and resolve it.
>> But chances are, if you have a problem (and you probably won't), it's
>> not going to be network traffic.

>
> Yes, I admit I may be prematurely optimising in the strictest sense,
> but surely it would be naive to assume that no thought is needed
> before implementing a database containing 100 million row datasets. If
> I can make sensible decisions beforehand then I will. I have already
> stated that I will change to InnoDB if it makes sense, but at the
> moment it doesn't make sense to me.
>


Which is another error programmers make. Why do you think you'll have
anywhere near 100M rows?

>
>>>> It is if you don't want them to go back and resubmit the form.
>>> That's not the problem I stated. The problem I stated was the user
>>> clicking the button twice from the same page beofore it has refreshed.

>> You can't prevent every problem. All you can do is handle them.

>
> But I can prevent it very simply using the random token idea. In fact
> this prevents both my problem and your problem plus any other
> potential problems (eg deliberate malicious multiple POSTs)
>


Go ahead and try it, but you're liable to be in for other problems -
like timing issues.

>> The easiest solution is to refresh immediately, perhaps with an
>> intermediate page, and then do the work.

>
> I'm trying to envisage how this would work but I can't.
> i.e.
> 1) User submits form data
> 2) Server gives immediate reply
> When is server work done? During the 2) script after outputing? How is
> the user's output refreshed when it's done?
> (I suspect I'm being stupid, sorry)
>


The server outputs most of a simple page and flushes the buffers. It
then does the work and outputs the rest of the page, which includes a
link to continue. Quite common.

>> Or just put a note on the page "Press the button only once".

> Sorry but yuk! :-/
>


Also quite common, even in some of the biggest shopping sites.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================

  Réponse avec citation
Vieux 01/03/2008, 20h33   #27
Jerry Stuckle
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Managing concurrency due to multiple submits

Jeremy@thebunnyshed.co.uk wrote:
> On Mar 1, 6:52 pm, Jerry Stuckle <jstuck...@attglobal.net> wrote:
>> Go ahead and try it, but you're liable to be in for other problems -
>> like timing issues.

>
> We seem to be going around in circles, or further wandering from my
> original problem which seems pretty pointless, but I would ask what
> you mean by this since it is pertinent to my OP (It's sort of what I
> was after in the first place - possible issues with my proposed
> solution).
>


Yes, we're going around in circles, and I've tried explaining to you before.

>> And don't count on the session to be a
>> method for serializing access. It works that way for now, with the
>> default file handler. But there is no guarantee it will remain that
>> way, nor that it will serialize access if you're using other handlers.

>
> Yes, I do take on board your warning about this, but even without the
> session serialisation effect the token will drastically reduce the
> time frame for potential conflicts, and using such current behaviour
> is surely better than just not bothering and hoping it's quick enough.
>


Nope. If the session access is no longer serialized, you have an even
bigger hole than if you didn't depend on it.

>> The server outputs most of a simple page and flushes the buffers. It
>> then does the work and outputs the rest of the page, which includes a
>> link to continue. Quite common.

>
> Ah ok, I see. I did ponder something similar myself for different
> problem. Again this doesn't remove the problem, just cuts down on the
> timeframe. It's certainly another potential solution though, so thanks.
>


And you'll drive yourself crazy trying to prevent every possible
problem. And you'll end up with so much code for things which are not
likely to occur your performance will suffer. And BTW - the more code
you add, the more chance you have for bugs.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================

  Réponse avec citation
Vieux 01/03/2008, 20h49   #28
Jeremy@thebunnyshed.co.uk
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Managing concurrency due to multiple submits

On Mar 1, 6:52pm, Jerry Stuckle <jstuck...@attglobal.net> wrote:
> Go ahead and try it, but you're liable to be in for other problems -
> like timing issues.


We seem to be going around in circles, or further wandering from my
original problem which seems pretty pointless, but I would ask what
you mean by this since it is pertinent to my OP (It's sort of what I
was after in the first place - possible issues with my proposed
solution).

> And don't count on the session to be a
> method for serializing access. It works that way for now, with the
> default file handler. But there is no guarantee it will remain that
> way, nor that it will serialize access if you're using other handlers.


Yes, I do take on board your warning about this, but even without the
session serialisation effect the token will drastically reduce the
time frame for potential conflicts, and using such current behaviour
is surely better than just not bothering and hoping it's quick enough.

> The server outputs most of a simple page and flushes the buffers. It
> then does the work and outputs the rest of the page, which includes a
> link to continue. Quite common.


Ah ok, I see. I did ponder something similar myself for different
problem. Again this doesn't remove the problem, just cuts down on the
timeframe. It's certainly another potential solution though, so thanks.
  Réponse avec citation
Vieux 01/03/2008, 21h13   #29
Jerry Stuckle
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Managing concurrency due to multiple submits

Michael Fesser wrote:
> .oO(Jerry Stuckle)
>
>> Jeremy@thebunnyshed.co.uk wrote:
>>
>>> I'm not talking about the script getting stuck, I'm talking about
>>> external factors delaying the script being called. (ie user clicks
>>> button, but webserver doesn't recieve the HTTP request for some
>>> seconds due to Internet bottlenecks etc. Second click could be routed
>>> differently and so arrive just milliseconds after the first one.

>> So, fix it with some javascript. Use javascript to enable button, then
>> disable it when it is clicked.

>
> This doesn't fix the main problem, but instead creates a new one. I've
> seen this totally stupid approach on some sites - if the first request
> doesn't make it to the server, you're stuck because the button is
> disabled and you can't try again. Pretty user-unfriendly.
>


But if the request never arrives, browsers will time out. That gives
you a chance to resubmit.

>>> Thanks for your . I'm not arguing that I'm necessarily correct,
>>> but I need to understand the why's and wherefor's of doing things a
>>> certain way. :-)

>> Redirecting doesn't allow them to go back to the previous page with the
>> back button on the browser.

>
> _If_ the redirect arrives in the browser before the user clicks the
> button a second time. There are things you simply can't control.
>
> Micha
>


Which is why I suggest using it with the combination of javascript above.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================

  Réponse avec citation
Vieux 01/03/2008, 21h44   #30
Michael Fesser
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Managing concurrency due to multiple submits

..oO(Jerry Stuckle)

>Jeremy@thebunnyshed.co.uk wrote:
>
>> I'm not talking about the script getting stuck, I'm talking about
>> external factors delaying the script being called. (ie user clicks
>> button, but webserver doesn't recieve the HTTP request for some
>> seconds due to Internet bottlenecks etc. Second click could be routed
>> differently and so arrive just milliseconds after the first one.

>
>So, fix it with some javascript. Use javascript to enable button, then
>disable it when it is clicked.


This doesn't fix the main problem, but instead creates a new one. I've
seen this totally stupid approach on some sites - if the first request
doesn't make it to the server, you're stuck because the button is
disabled and you can't try again. Pretty user-unfriendly.

>> Thanks for your . I'm not arguing that I'm necessarily correct,
>> but I need to understand the why's and wherefor's of doing things a
>> certain way. :-)

>
>Redirecting doesn't allow them to go back to the previous page with the
>back button on the browser.


_If_ the redirect arrives in the browser before the user clicks the
button a second time. There are things you simply can't control.

Micha
  Réponse avec citation
Vieux 01/03/2008, 23h22   #31
The Natural Philosopher
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Managing concurrency due to multiple submits

Jerry Stuckle wrote:
> The Natural Philosopher wrote:
>> Jeremy@thebunnyshed.co.uk wrote:
>>> On Mar 1, 12:41 pm, The Natural Philosopher <a...@b.c> wrote:
>>>
>>>> Its not clear as to whether you are using MySql or just raw files as
>>>> the
>>>> database.
>>> Yes, MySQL. (hence the table type comments)
>>>
>>>> If using MYSQL simply LOCK the tables and unlock them after they are
>>>> updated.
>>> That's a thought yeah. Don't know much about locks as I'm a fair
>>> newbie still, but I seem to remember that MyISAM tables lock the
>>> entire table, and I would have to lock several tables at once. Dunno
>>> if this will cause performance problems due to other users being
>>> locked out. I will have to gen up on the lock mechanics a bit, but
>>> thanks :-)

>>
>> Basically the way to turn several accesses into an 'atomic' access is
>> to LOCK all the tables you use for read, which means others can read,
>> but not write, do your stuff and UNLOCK the lot when you have finished.
>>
>> Other write threads will simply be suspended pending your completion.
>>
>> You may want to put timeouts and stuff in there ..because..
>>
>> ..If the original thread crashes, you will have stale locks. Not sure
>> how you clear those. Probably off to a mysql group for better info.
>>
>>
>>

>
> MySQL will release the locks when the connection closes. But it will
> not back out the partially-inserted data.
>

First good point you've made all year. ;-)
  Réponse avec citation
Vieux 02/03/2008, 01h23   #32
Norman Peelman
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Managing concurrency due to multiple submits

Jerry Stuckle wrote:
> Norman Peelman wrote:
>> Jeremy@thebunnyshed.co.uk wrote:
>>> Hi all,
>>>
>>> I have a situation where the user can add an item to my database by
>>> clicking an add button which POSTs the form details and they are added
>>> to the DB.
>>>
>>> The addition requires manipulation of several tables, so I don't want
>>> the PHP script getting killed half way through and leaving the DB in
>>> an inconsistant state. I see that the ignore_user_abort() function
>>> will do that for me. All good.
>>>
>>> However, I pondered what would happen if the user clicked the add
>>> button twice in quick succession. The first click would kick off the
>>> PHP script which would not get aborted by the second click do to my
>>> ignore_user_abort() call. The second click would then (I assume?) kick
>>> off another instance of the script which would also try and add the
>>> item. I would have two scripts both working on inserting the same
>>> object and I can forsee lots of muck ups.
>>>
>>> My tables are currently MyISAM for performance reasons, and also
>>> because they have FULLTEXT indexes on them, so I have no native DB
>>> transactional support.
>>>
>>> I am pondering the idea of writing a random transaction key to the
>>> form so that once the first script gets kicked off, it marks that key
>>> as "processed" in the session data, so that the second script can
>>> check it and abort. This will mean I have to write out the session
>>> data mid script but I don't see that as a problem.
>>>
>>> Any recommendations on whether this is a good idea or not? It's going
>>> to be a real arse ache if I have to convert my tables to InnoDB :-/
>>>
>>> Many thanks,
>>> Jeremy

>>
>>
>> if (isset($_SESSION['running']) && ($_SESSION['running'] === TRUE))
>> {
>> //abort/redirect...
>> }
>> $_SESSION['running'] = TRUE;
>> // do stuff
>> $_SESSION['running'] = FALSE;
>>
>>
>> ...should avoid muliple fast clicks but you would need to add some
>> info/code to prevent the user from adding the same item over and over
>> anyway (if you haven't already done so). Untested...
>>
>>
>>

>
> Which will never be true with the default file session handler because
> sessions are single threaded. So the second script will wait for the
> first one's session to end.
>
> However, change session handlers and that may not be true.
>


What about a cache handler like APC? Same method but store a flag in
the server wide user space cache where the key is the session id:

if ($flag = apc_fetch("$session_id"))
{
//abort/redirect...
}
// set block
apc_store("$session_id",TRUE,$ttl); // $ttl = 30 seconds??
// do stuff

// free block
apc_delete("$session_id");


--
Norman
Registered Linux user #461062
  Réponse avec citation
Vieux 02/03/2008, 03h01   #33
Jerry Stuckle
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Managing concurrency due to multiple submits

Norman Peelman wrote:
> Jerry Stuckle wrote:
>> Norman Peelman wrote:
>>> Jeremy@thebunnyshed.co.uk wrote:
>>>> Hi all,
>>>>
>>>> I have a situation where the user can add an item to my database by
>>>> clicking an add button which POSTs the form details and they are added
>>>> to the DB.
>>>>
>>>> The addition requires manipulation of several tables, so I don't want
>>>> the PHP script getting killed half way through and leaving the DB in
>>>> an inconsistant state. I see that the ignore_user_abort() function
>>>> will do that for me. All good.
>>>>
>>>> However, I pondered what would happen if the user clicked the add
>>>> button twice in quick succession. The first click would kick off the
>>>> PHP script which would not get aborted by the second click do to my
>>>> ignore_user_abort() call. The second click would then (I assume?) kick
>>>> off another instance of the script which would also try and add the
>>>> item. I would have two scripts both working on inserting the same
>>>> object and I can forsee lots of muck ups.
>>>>
>>>> My tables are currently MyISAM for performance reasons, and also
>>>> because they have FULLTEXT indexes on them, so I have no native DB
>>>> transactional support.
>>>>
>>>> I am pondering the idea of writing a random transaction key to the
>>>> form so that once the first script gets kicked off, it marks that key
>>>> as "processed" in the session data, so that the second script can
>>>> check it and abort. This will mean I have to write out the session
>>>> data mid script but I don't see that as a problem.
>>>>
>>>> Any recommendations on whether this is a good idea or not? It's going
>>>> to be a real arse ache if I have to convert my tables to InnoDB :-/
>>>>
>>>> Many thanks,
>>>> Jeremy
>>>
>>>
>>> if (isset($_SESSION['running']) && ($_SESSION['running'] === TRUE))
>>> {
>>> //abort/redirect...
>>> }
>>> $_SESSION['running'] = TRUE;
>>> // do stuff
>>> $_SESSION['running'] = FALSE;
>>>
>>>
>>> ...should avoid muliple fast clicks but you would need to add some
>>> info/code to prevent the user from adding the same item over and over
>>> anyway (if you haven't already done so). Untested...
>>>
>>>
>>>

>>
>> Which will never be true with the default file session handler because
>> sessions are single threaded. So the second script will wait for the
>> first one's session to end.
>>
>> However, change session handlers and that may not be true.
>>

>
> What about a cache handler like APC? Same method but store a flag in
> the server wide user space cache where the key is the session id:
>
> if ($flag = apc_fetch("$session_id"))
> {
> //abort/redirect...
> }
> // set block
> apc_store("$session_id",TRUE,$ttl); // $ttl = 30 seconds??
> // do stuff
>
> // free block
> apc_delete("$session_id");
>
>


That's a possibility, if you can find a hosting company which has APC or
similar installed. Most don't.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================

  Réponse avec citation
Vieux 02/03/2008, 05h05   #34
Norman Peelman
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Managing concurrency due to multiple submits

Jerry Stuckle wrote:
> Norman Peelman wrote:
>> Jerry Stuckle wrote:
>>> Norman Peelman wrote:
>>>> Jeremy@thebunnyshed.co.uk wrote:
>>>>> Hi all,
>>>>>
>>>>> I have a situation where the user can add an item to my database by
>>>>> clicking an add button which POSTs the form details and they are added
>>>>> to the DB.
>>>>>
>>>>> The addition requires manipulation of several tables, so I don't want
>>>>> the PHP script getting killed half way through and leaving the DB in
>>>>> an inconsistant state. I see that the ignore_user_abort() function
>>>>> will do that for me. All good.
>>>>>
>>>>> However, I pondered what would happen if the user clicked the add
>>>>> button twice in quick succession. The first click would kick off the
>>>>> PHP script which would not get aborted by the second click do to my
>>>>> ignore_user_abort() call. The second click would then (I assume?) kick
>>>>> off another instance of the script which would also try and add the
>>>>> item. I would have two scripts both working on inserting the same
>>>>> object and I can forsee lots of muck ups.
>>>>>
>>>>> My tables are currently MyISAM for performance reasons, and also
>>>>> because they have FULLTEXT indexes on them, so I have no native DB
>>>>> transactional support.
>>>>>
>>>>> I am pondering the idea of writing a random transaction key to the
>>>>> form so that once the first script gets kicked off, it marks that key
>>>>> as "processed" in the session data, so that the second script can
>>>>> check it and abort. This will mean I have to write out the session
>>>>> data mid script but I don't see that as a problem.
>>>>>
>>>>> Any recommendations on whether this is a good idea or not? It's going
>>>>> to be a real arse ache if I have to convert my tables to InnoDB :-/
>>>>>
>>>>> Many thanks,
>>>>> Jeremy
>>>>
>>>>
>>>> if (isset($_SESSION['running']) && ($_SESSION['running'] === TRUE))
>>>> {
>>>> //abort/redirect...
>>>> }
>>>> $_SESSION['running'] = TRUE;
>>>> // do stuff
>>>> $_SESSION['running'] = FALSE;
>>>>
>>>>
>>>> ...should avoid muliple fast clicks but you would need to add some
>>>> info/code to prevent the user from adding the same item over and
>>>> over anyway (if you haven't already done so). Untested...
>>>>
>>>>
>>>>
>>>
>>> Which will never be true with the default file session handler
>>> because sessions are single threaded. So the second script will wait
>>> for the first one's session to end.
>>>
>>> However, change session handlers and that may not be true.
>>>

>>
>> What about a cache handler like APC? Same method but store a flag in
>> the server wide user space cache where the key is the session id:
>>
>> if ($flag = apc_fetch("$session_id"))
>> {
>> //abort/redirect...
>> }
>> // set block
>> apc_store("$session_id",TRUE,$ttl); // $ttl = 30 seconds??
>> // do stuff
>>
>> // free block
>> apc_delete("$session_id");
>>
>>

>
> That's a possibility, if you can find a hosting company which has APC or
> similar installed. Most don't.
>


I do my own hosting for now so I keep forgetting.

--
Norman
Registered Linux user #461062
  Réponse avec citation
Vieux 02/03/2008, 05h12   #35
Norman Peelman
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Managing concurrency due to multiple submits

Jerry Stuckle wrote:
> Norman Peelman wrote:
>> Jerry Stuckle wrote:
>>> Norman Peelman wrote:
>>>> Jeremy@thebunnyshed.co.uk wrote:
>>>>> Hi all,
>>>>>
>>>>> I have a situation where the user can add an item to my database by
>>>>> clicking an add button which POSTs the form details and they are added
>>>>> to the DB.
>>>>>
>>>>> The addition requires manipulation of several tables, so I don't want
>>>>> the PHP script getting killed half way through and leaving the DB in
>>>>> an inconsistant state. I see that the ignore_user_abort() function
>>>>> will do that for me. All good.
>>>>>
>>>>> However, I pondered what would happen if the user clicked the add
>>>>> button twice in quick succession. The first click would kick off the
>>>>> PHP script which would not get aborted by the second click do to my
>>>>> ignore_user_abort() call. The second click would then (I assume?) kick
>>>>> off another instance of the script which would also try and add the
>>>>> item. I would have two scripts both working on inserting the same
>>>>> object and I can forsee lots of muck ups.
>>>>>
>>>>> My tables are currently MyISAM for performance reasons, and also
>>>>> because they have FULLTEXT indexes on them, so I have no native DB
>>>>> transactional support.
>>>>>
>>>>> I am pondering the idea of writing a random transaction key to the
>>>>> form so that once the first script gets kicked off, it marks that key
>>>>> as "processed" in the session data, so that the second script can
>>>>> check it and abort. This will mean I have to write out the session
>>>>> data mid script but I don't see that as a problem.
>>>>>
>>>>> Any recommendations on whether this is a good idea or not? It's going
>>>>> to be a real arse ache if I have to convert my tables to InnoDB :-/
>>>>>
>>>>> Many thanks,
>>>>> Jeremy
>>>>
>>>>
>>>> if (isset($_SESSION['running']) && ($_SESSION['running'] === TRUE))
>>>> {
>>>> //abort/redirect...
>>>> }
>>>> $_SESSION['running'] = TRUE;
>>>> // do stuff
>>>> $_SESSION['running'] = FALSE;
>>>>
>>>>
>>>> ...should avoid muliple fast clicks but you would need to add some
>>>> info/code to prevent the user from adding the same item over and
>>>> over anyway (if you haven't already done so). Untested...
>>>>
>>>>
>>>>
>>>
>>> Which will never be true with the default file session handler
>>> because sessions are single threaded. So the second script will wait
>>> for the first one's session to end.
>>>
>>> However, change session handlers and that may not be true.
>>>

>>
>> What about a cache handler like APC? Same method but store a flag in
>> the server wide user space cache where the key is the session id:
>>
>> if ($flag = apc_fetch("$session_id"))
>> {
>> //abort/redirect...
>> }
>> // set block
>> apc_store("$session_id",TRUE,$ttl); // $ttl = 30 seconds??
>> // do stuff
>>
>> // free block
>> apc_delete("$session_id");
>>
>>

>
> That's a possibility, if you can find a hosting company which has APC or
> similar installed. Most don't.
>


Why not just have a table set up for this. Not in the data itself,
just a separate table to hold the session_id's that are currently
writing. Still same code logic. Which is almost the same as using the db
as the session handler, isn't it. When going that route does setting a
session variable get written to the db at that moment or is there a delay?

key: session_id, value: NULL | 1

key would be indexed of course.

--
Norman
Registered Linux user #461062
  Réponse avec citation
Vieux 02/03/2008, 14h08   #36
Jerry Stuckle
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Managing concurrency due to multiple submits

Norman Peelman wrote:
> Jerry Stuckle wrote:
>> Norman Peelman wrote:
>>> Jerry Stuckle wrote:
>>>> Norman Peelman wrote:
>>>>> Jeremy@thebunnyshed.co.uk wrote:
>>>>>> Hi all,
>>>>>>
>>>>>> I have a situation where the user can add an item to my database by
>>>>>> clicking an add button which POSTs the form details and they are
>>>>>> added
>>>>>> to the DB.
>>>>>>
>>>>>> The addition requires manipulation of several tables, so I don't want
>>>>>> the PHP script getting killed half way through and leaving the DB in
>>>>>> an inconsistant state. I see that the ignore_user_abort() function
>>>>>> will do that for me. All good.
>>>>>>
>>>>>> However, I pondered what would happen if the user clicked the add
>>>>>> button twice in quick succession. The first click would kick off the
>>>>>> PHP script which would not get aborted by the second click do to my
>>>>>> ignore_user_abort() call. The second click would then (I assume?)
>>>>>> kick
>>>>>> off another instance of the script which would also try and add the
>>>>>> item. I would have two scripts both working on inserting the same
>>>>>> object and I can forsee lots of muck ups.
>>>>>>
>>>>>> My tables are currently MyISAM for performance reasons, and also
>>>>>> because they have FULLTEXT indexes on them, so I have no native DB
>>>>>> transactional support.
>>>>>>
>>>>>> I am pondering the idea of writing a random transaction key to the
>>>>>> form so that once the first script gets kicked off, it marks that key
>>>>>> as "processed" in the session data, so that the second script can
>>>>>> check it and abort. This will mean I have to write out the session
>>>>>> data mid script but I don't see that as a problem.
>>>>>>
>>>>>> Any recommendations on whether this is a good idea or not? It's going
>>>>>> to be a real arse ache if I have to convert my tables to InnoDB :-/
>>>>>>
>>>>>> Many thanks,
>>>>>> Jeremy
>>>>>
>>>>>
>>>>> if (isset($_SESSION['running']) && ($_SESSION['running'] === TRUE))
>>>>> {
>>>>> //abort/redirect...
>>>>> }
>>>>> $_SESSION['running'] = TRUE;
>>>>> // do stuff
>>>>> $_SESSION['running'] = FALSE;
>>>>>
>>>>>
>>>>> ...should avoid muliple fast clicks but you would need to add some
>>>>> info/code to prevent the user from adding the same item over and
>>>>> over anyway (if you haven't already done so). Untested...
>>>>>
>>>>>
>>>>>
>>>>
>>>> Which will never be true with the default file session handler
>>>> because sessions are single threaded. So the second script will
>>>> wait for the first one's session to end.
>>>>
>>>> However, change session handlers and that may not be true.
>>>>
>>>
>>> What about a cache handler like APC? Same method but store a flag
>>> in the server wide user space cache where the key is the session id:
>>>
>>> if ($flag = apc_fetch("$session_id"))
>>> {
>>> //abort/redirect...
>>> }
>>> // set block
>>> apc_store("$session_id",TRUE,$ttl); // $ttl = 30 seconds??
>>> // do stuff
>>>
>>> // free block
>>> apc_delete("$session_id");
>>>
>>>

>>
>> That's a possibility, if you can find a hosting company which has APC
>> or similar installed. Most don't.
>>

>
> Why not just have a table set up for this. Not in the data itself,
> just a separate table to hold the session_id's that are currently
> writing. Still same code logic. Which is almost the same as using the db
> as the session handler, isn't it. When going that route does setting a
> session variable get written to the db at that moment or is there a delay?
>
> key: session_id, value: NULL | 1
>
> key would be indexed of course.
>


Yes, there can be a delay, but it shouldn't cause a problem. But more
thinking about it and neither is a good solution. What happens when the
first action finishes? If it clears the session id, then another entry
can get in there. If it doesn't clear the session id, then session id's
add up, and the person won't be able to add another item to the tables.

Nope, won't work.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================

  Réponse avec citation
Vieux 02/03/2008, 15h50   #37
Norman Peelman
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Managing concurrency due to multiple submits

Jerry Stuckle wrote:
> Norman Peelman wrote:
>> Jerry Stuckle wrote:
>>> Norman Peelman wrote:
>>>> Jerry Stuckle wrote:
>>>>> Norman Peelman wrote:
>>>>>> Jeremy@thebunnyshed.co.uk wrote:
>>>>>>> Hi all,
>>>>>>>
>>>>>>> I have a situation where the user can add an item to my database by
>>>>>>> clicking an add button which POSTs the form details and they are
>>>>>>> added
>>>>>>> to the DB.
>>>>>>>
>>>>>>> The addition requires manipulation of several tables, so I don't
>>>>>>> want
>>>>>>> the PHP script getting killed half way through and leaving the DB in
>>>>>>> an inconsistant state. I see that the ignore_user_abort() function
>>>>>>> will do that for me. All good.
>>>>>>>
>>>>>>> However, I pondered what would happen if the user clicked the add
>>>>>>> button twice in quick succession. The first click would kick off the
>>>>>>> PHP script which would not get aborted by the second click do to my
>>>>>>> ignore_user_abort() call. The second click would then (I assume?)
>>>>>>> kick
>>>>>>> off another instance of the script which would also try and add the
>>>>>>> item. I would have two scripts both working on inserting the same
>>>>>>> object and I can forsee lots of muck ups.
>>>>>>>
>>>>>>> My tables are currently MyISAM for performance reasons, and also
>>>>>>> because they have FULLTEXT indexes on them, so I have no native DB
>>>>>>> transactional support.
>>>>>>>
>>>>>>> I am pondering the idea of writing a random transaction key to the
>>>>>>> form so that once the first script gets kicked off, it marks that
>>>>>>> key
>>>>>>> as "processed" in the session data, so that the second script can
>>>>>>> check it and abort. This will mean I have to write out the session
>>>>>>> data mid script but I don't see that as a problem.
>>>>>>>
>>>>>>> Any recommendations on whether this is a good idea or not? It's
>>>>>>> going
>>>>>>> to be a real arse ache if I have to convert my tables to InnoDB :-/
>>>>>>>
>>>>>>> Many thanks,
>>>>>>> Jeremy
>>>>>>
>>>>>>
>>>>>> if (isset($_SESSION['running']) && ($_SESSION['running'] === TRUE))
>>>>>> {
>>>>>> //abort/redirect...
>>>>>> }
>>>>>> $_SESSION['running'] = TRUE;
>>>>>> // do stuff
>>>>>> $_SESSION['running'] = FALSE;
>>>>>>
>>>>>>
>>>>>> ...should avoid muliple fast clicks but you would need to add some
>>>>>> info/code to prevent the user from adding the same item over and
>>>>>> over anyway (if you haven't already done so). Untested...
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>> Which will never be true with the default file session handler
>>>>> because sessions are single threaded. So the second script will
>>>>> wait for the first one's session to end.
>>>>>
>>>>> However, change session handlers and that may not be true.
>>>>>
>>>>
>>>> What about a cache handler like APC? Same method but store a flag
>>>> in the server wide user space cache where the key is the session id:
>>>>
>>>> if ($flag = apc_fetch("$session_id"))
>>>> {
>>>> //abort/redirect...
>>>> }
>>>> // set block
>>>> apc_store("$session_id",TRUE,$ttl); // $ttl = 30 seconds??
>>>> // do stuff
>>>>
>>>> // free block
>>>> apc_delete("$session_id");
>>>>
>>>>
>>>
>>> That's a possibility, if you can find a hosting company which has APC
>>> or similar installed. Most don't.
>>>

>>
>> Why not just have a table set up for this. Not in the data itself,
>> just a separate table to hold the session_id's that are currently
>> writing. Still same code logic. Which is almost the same as using the
>> db as the session handler, isn't it. When going that route does
>> setting a session variable get written to the db at that moment or is
>> there a delay?
>>
>> key: session_id, value: NULL | 1
>>
>> key would be indexed of course.
>>

>
> Yes, there can be a delay, but it shouldn't cause a problem. But more
> thinking about it and neither is a good solution. What happens when the
> first action finishes? If it clears the session id, then another entry
> can get in there.


I was assuming he has logic to prevent duplicate entries in place. He
should be aborting on a duplicate insert anyway or better yet:

INSERT ... ON DUPLICATE KEY UPDATE field(s) = field(s) would solve the
problem, wouldn't it. Used on the initial INSERT would simply do nothing
since nothing has changed.

edits would be regular UPDATE ...

> If it doesn't clear the session id, then session id's
> add up, and the person won't be able to add another item to the tables.
>
> Nope, won't work.
>


excuse my horrible pseudo code:

key: session_id, value: NULL | 1
ttl: timestamp

$running = "SELECT session_id, ttl FROM <table> WHERE session_id =
'$session_id';

if ($running && ((time() - ttl) < 10)) abort;
else
//set session running
INSERT INTO <table> VALUES ('$session_id',NOW())
// get rid of all outdated entries
DELETE FROM <table> WHERE (TIMESTAMP() - ttl) > 10"
rest of code
DELETE FROM <table> WHERE session_id = '$session_id'


--
Norman
Registered Linux user #461062
-Have you been to www.php.net yet?-
  Réponse avec citation
Vieux 02/03/2008, 16h10   #38
Jerry Stuckle
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Managing concurrency due to multiple submits

Norman Peelman wrote:
> Jerry Stuckle wrote:
>> Norman Peelman wrote:
>>> Jerry Stuckle wrote:
>>>> Norman Peelman wrote:
>>>>> Jerry Stuckle wrote:
>>>>>> Norman Peelman wrote:
>>>>>>> Jeremy@thebunnyshed.co.uk wrote:
>>>>>>>> Hi all,
>>>>>>>>
>>>>>>>> I have a situation where the user can add an item to my database by
>>>>>>>> clicking an add button which POSTs the form details and they are
>>>>>>>> added
>>>>>>>> to the DB.
>>>>>>>>
>>>>>>>> The addition requires manipulation of several tables, so I don't
>>>>>>>> want
>>>>>>>> the PHP script getting killed half way through and leaving the
>>>>>>>> DB in
>>>>>>>> an inconsistant state. I see that the ignore_user_abort() function
>>>>>>>> will do that for me. All good.
>>>>>>>>
>>>>>>>> However, I pondered what would happen if the user clicked the add
>>>>>>>> button twice in quick succession. The first click would kick off
>>>>>>>> the
>>>>>>>> PHP script which would not get aborted by the second click do to my
>>>>>>>> ignore_user_abort() call. The second click would then (I
>>>>>>>> assume?) kick
>>>>>>>> off another instance of the script which would also try and add the
>>>>>>>> item. I would have two scripts both working on inserting the same
>>>>>>>> object and I can forsee lots of muck ups.
>>>>>>>>
>>>>>>>> My tables are currently MyISAM for performance reasons, and also
>>>>>>>> because they have FULLTEXT indexes on them, so I have no native DB
>>>>>>>> transactional support.
>>>>>>>>
>>>>>>>> I am pondering the idea of writing a random transaction key to the
>>>>>>>> form so that once the first script gets kicked off, it marks
>>>>>>>> that key
>>>>>>>> as "processed" in the session data, so that the second script can
>>>>>>>> check it and abort. This will mean I have to write out the session
>>>>>>>> data mid script but I don't see that as a problem.
>>>>>>>>
>>>>>>>> Any recommendations on whether this is a good idea or not? It's
>>>>>>>> going
>>>>>>>> to be a real arse ache if I have to convert my tables to InnoDB :-/
>>>>>>>>
>>>>>>>> Many thanks,
>>>>>>>> Jeremy
>>>>>>>
>>>>>>>
>>>>>>> if (isset($_SESSION['running']) && ($_SESSION['running'] === TRUE))
>>>>>>> {
>>>>>>> //abort/redirect...
>>>>>>> }
>>>>>>> $_SESSION['running'] = TRUE;
>>>>>>> // do stuff
>>>>>>> $_SESSION['running'] = FALSE;
>>>>>>>
>>>>>>>
>>>>>>> ...should avoid muliple fast clicks but you would need to add
>>>>>>> some info/code to prevent the user from adding the same item over
>>>>>>> and over anyway (if you haven't already done so). Untested...
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>> Which will never be true with the default file session handler
>>>>>> because sessions are single threaded. So the second script will
>>>>>> wait for the first one's session to end.
>>>>>>
>>>>>> However, change session handlers and that may not be true.
>>>>>>
>>>>>
>>>>> What about a cache handler like APC? Same method but store a flag
>>>>> in the server wide user space cache where the key is the session id:
>>>>>
>>>>> if ($flag = apc_fetch("$session_id"))
>>>>> {
>>>>> //abort/redirect...
>>>>> }
>>>>> // set block
>>>>> apc_store("$session_id",TRUE,$ttl); // $ttl = 30 seconds??
>>>>> // do stuff
>>>>>
>>>>> // free block
>>>>> apc_delete("$session_id");
>>>>>
>>>>>
>>>>
>>>> That's a possibility, if you can find a hosting company which has
>>>> APC or similar installed. Most don't.
>>>>
>>>
>>> Why not just have a table set up for this. Not in the data itself,
>>> just a separate table to hold the session_id's that are currently
>>> writing. Still same code logic. Which is almost the same as using the
>>> db as the session handler, isn't it. When going that route does
>>> setting a session variable get written to the db at that moment or is
>>> there a delay?
>>>
>>> key: session_id, value: NULL | 1
>>>
>>> key would be indexed of course.
>>>

>>
>> Yes, there can be a delay, but it shouldn't cause a problem. But more
>> thinking about it and neither is a good solution. What happens when
>> the first action finishes? If it clears the session id, then another
>> entry can get in there.

>
> I was assuming he has logic to prevent duplicate entries in place. He
> should be aborting on a duplicate insert anyway or better yet:
>
> INSERT ... ON DUPLICATE KEY UPDATE field(s) = field(s) would solve the
> problem, wouldn't it. Used on the initial INSERT would simply do nothing
> since nothing has changed.
>
> edits would be regular UPDATE ...
>
> > If it doesn't clear the session id, then session id's
> > add up, and the person won't be able to add another item to the tables.
> >
> > Nope, won't work.
> >

>
> excuse my horrible pseudo code:
>
> key: session_id, value: NULL | 1
> ttl: timestamp
>
> $running = "SELECT session_id, ttl FROM <table> WHERE session_id =
> '$session_id';
>
> if ($running && ((time() - ttl) < 10)) abort;
> else
> //set session running
> INSERT INTO <table> VALUES ('$session_id',NOW())
> // get rid of all outdated entries
> DELETE FROM <table> WHERE (TIMESTAMP() - ttl) > 10"
> rest of code
> DELETE FROM <table> WHERE session_id = '$session_id'
>
>


If he had that logic in place, then we wouldn't need the workarounds.
If someone clicked a button twice, the second one would be rejected.

However, more often than not, the data itself may or may not be
duplicated. For instance, if it were a forum, it could be quite
possible to add the same message to the forum - a "lol" or "Thanks"
similar is a pretty common duplicate message.

More likely, he's adding something and getting a new primary key, i.e.
via an autoincrement column, in which case a duplicate add would create
a new primary key.

And putting a time limit on it may or may not resolve the problem. How
much is too long? Or too short? Either one can be a problem.


--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================

  Réponse avec citation
Vieux 02/03/2008, 19h32   #39
petersprc
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Managing concurrency due to multiple submits

Hi,

There's some more detail on locking in the session_write_close page.

session data is locked to prevent concurrent writes only one script
may operate on a session at any time. When using framesets together
with sessions you will experience the frames loading one by one due to
this locking. You can reduce the time needed to load all the frames by
ending the session as soon as all changes to session variables are
done.

<http://us2.php.net/manual/en/function.session-write-close.php>

This is implemented in the default session handler in ext/session/
mod_files.c with a call to flock.

Regards,

John Peters

On Mar 1, 7:49 am, Jer...@thebunnyshed.co.uk wrote:
> On Mar 1, 4:34 am,petersprc<peters...@gmail.com> wrote:
>
> > Usingsessionsshould work fine. Technically speaking, some less-used
> > session handlers don't guaranteeexclusivesession access, but the
> > default one does.

>
> Ah! Now that's interesting! I was worried that using a key in the
> session data would still cause problems if the second script managed
> to read the key before the first script managed to write away the fact
> that it was processing that key.
>
> I've just had a quick ponder over the session docs at php.net but
> can't find anything regarding exclusive access other than a user
> comment that session_start() will block if another script it still
> using the session.
>
> If this is true it could solve all my problems! Thanks!
>
> > FYI, another way is to insert that randomly generated token into a
> > table with a UNIQUE constraint. Other locking mechanisms include flock
> > and sem_acquire...

>
> Thanks I will take a look at those options too. The token in the DB
> doesn't particularly appeal to me since you then have extra storage
> and index overhead, but it is certainly an option thanks.
>
> Cheers,
> Jeremy


  Réponse avec citation
Vieux 02/03/2008, 22h43   #40
Jerry Stuckle
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Managing concurrency due to multiple submits

Norman Peelman wrote:
> Jerry Stuckle wrote:
>> Norman Peelman wrote:
>>> Jerry Stuckle wrote:
>>>> Norman Peelman wrote:
>>>>> Jerry Stuckle wrote:
>>>>>> Norman Peelman wrote:
>>>>>>> Jerry Stuckle wrote:
>>>>>>>> Norman Peelman wrote:
>>>>>>>>> Jeremy@thebunnyshed.co.uk wrote:
>>>>>>>>>> Hi all,
>>>>>>>>>>
>>>>>>>>>> I have a situation where the user can add an item to my
>>>>>>>>>> database by
>>>>>>>>>> clicking an add button which POSTs the form details and they
>>>>>>>>>> are added
>>>>>>>>>> to the DB.
>>>>>>>>>>
>>>>>>>>>> The addition requires manipulation of several tables, so I
>>>>>>>>>> don't want
>>>>>>>>>> the PHP script getting killed half way through and leaving the
>>>>>>>>>> DB in
>>>>>>>>>> an inconsistant state. I see that the ignore_user_abort()
>>>>>>>>>> function
>>>>>>>>>> will do that for me. All good.
>>>>>>>>>>
>>>>>>>>>> However, I pondered what would happen if the user clicked the add
>>>>>>>>>> button twice in quick succession. The first click would kick
>>>>>>>>>> off the
>>>>>>>>>> PHP script which would not get aborted by the second click do
>>>>>>>>>> to my
>>>>>>>>>> ignore_user_abort() call. The second click would then (I
>>>>>>>>>> assume?) kick
>>>>>>>>>> off another instance of the script which would also try and
>>>>>>>>>> add the
>>>>>>>>>> item. I would have two scripts both working on inserting the
>>>>>>>>>> same
>>>>>>>>>> object and I can forsee lots of muck ups.
>>>>>>>>>>
>>>>>>>>>> My tables are currently MyISAM for performance reasons, and also
>>>>>>>>>> because they have FULLTEXT indexes on them, so I have no
>>>>>>>>>> native DB
>>>>>>>>>> transactional support.
>>>>>>>>>>
>>>>>>>>>> I am pondering the idea of writing a random transaction key to
>>>>>>>>>> the
>>>>>>>>>> form so that once the first script gets kicked off, it marks
>>>>>>>>>> that key
>>>>>>>>>> as "processed" in the session data, so that the second script can
>>>>>>>>>> check it and abort. This will mean I have to write out the
>>>>>>>>>> session
>>>>>>>>>> data mid script but I don't see that as a problem.
>>>>>>>>>>
>>>>>>>>>> Any recommendations on whether this is a good idea or not?
>>>>>>>>>> It's going
>>>>>>>>>> to be a real arse ache if I have to convert my tables to
>>>>>>>>>> InnoDB :-/
>>>>>>>>>>
>>>>>>>>>> Many thanks,
>>>>>>>>>> Jeremy
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> if (isset($_SESSION['running']) && ($_SESSION['running'] ===
>>>>>>>>> TRUE))
>>>>>>>>> {
>>>>>>>>> //abort/redirect...
>>>>>>>>> }
>>>>>>>>> $_SESSION['running'] = TRUE;
>>>>>>>>> // do stuff
>>>>>>>>> $_SESSION['running'] = FALSE;
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> ...should avoid muliple fast clicks but you would need to add
>>>>>>>>> some info/code to prevent the user from adding the same item
>>>>>>>>> over and over anyway (if you haven't already done so). Untested...
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>> Which will never be true with the default file session handler
>>>>>>>> because sessions are single threaded. So the second script will
>>>>>>>> wait for the first one's session to end.
>>>>>>>>
>>>>>>>> However, change session handlers and that may not be true.
>>>>>>>>
>>>>>>>
>>>>>>> What about a cache handler like APC? Same method but store a
>>>>>>> flag in the server wide user space cache where the key is the
>>>>>>> session id:
>>>>>>>
>>>>>>> if ($flag = apc_fetch("$session_id"))
>>>>>>> {
>>>>>>> //abort/redirect...
>>>>>>> }
>>>>>>> // set block
>>>>>>> apc_store("$session_id",TRUE,$ttl); // $ttl = 30 seconds??
>>>>>>> // do stuff
>>>>>>>
>>>>>>> // free block
>>>>>>> apc_delete("$session_id");
>>>>>>>
>>>>>>>
>>>>>>
>>>>>> That's a possibility, if you can find a hosting company which has
>>>>>> APC or similar installed. Most don't.
>>>>>>
>>>>>
>>>>> Why not just have a table set up for this. Not in the data
>>>>> itself, just a separate table to hold the session_id's that are
>>>>> currently writing. Still same code logic. Which is almost the same
>>>>> as using the db as the session handler, isn't it. When going that
>>>>> route does setting a session variable get written to the db at that
>>>>> moment or is there a delay?
>>>>>
>>>>> key: session_id, value: NULL | 1
>>>>>
>>>>> key would be indexed of course.
>>>>>
>>>>
>>>> Yes, there can be a delay, but it shouldn't cause a problem. But
>>>> more thinking about it and neither is a good solution. What happens
>>>> when the first action finishes? If it clears the session id, then
>>>> another entry can get in there.
>>>
>>> I was assuming he has logic to prevent duplicate entries in place.
>>> He should be aborting on a duplicate insert anyway or better yet:
>>>
>>> INSERT ... ON DUPLICATE KEY UPDATE field(s) = field(s) would solve
>>> the problem, wouldn't it. Used on the initial INSERT would simply do
>>> nothing since nothing has changed.
>>>
>>> edits would be regular UPDATE ...
>>>
>>> > If it doesn't clear the session id, then session id's
>>> > add up, and the person won't be able to add another item to the
>>> tables.
>>> >
>>> > Nope, won't work.
>>> >
>>>
>>> excuse my horrible pseudo code:
>>>
>>> key: session_id, value: NULL | 1
>>> ttl: timestamp
>>>
>>> $running = "SELECT session_id, ttl FROM <table> WHERE session_id =
>>> '$session_id';
>>>
>>> if ($running && ((time() - ttl) < 10)) abort;
>>> else
>>> //set session running
>>> INSERT INTO <table> VALUES ('$session_id',NOW())
>>> // get rid of all outdated entries
>>> DELETE FROM <table> WHERE (TIMESTAMP() - ttl) > 10"
>>> rest of code
>>> DELETE FROM <table> WHERE session_id = '$session_id'
>>>
>>>

>>
>> If he had that logic in place, then we wouldn't need the workarounds.
>> If someone clicked a button twice, the second one would be rejected.
>>
>> However, more often than not, the data itself may or may not be
>> duplicated. For instance, if it were a forum, it could be quite
>> possible to add the same message to the forum - a "lol" or "Thanks"
>> similar is a pretty common duplicate message.
>>
>> More likely, he's adding something and getting a new primary key, i.e.
>> via an autoincrement column, in which case a duplicate add would
>> create a new primary key.
>>
>> And putting a time limit on it may or may not resolve the problem.
>> How much is too long? Or too short? Either one can be a problem.
>>
>>

>
> Jerry,
>
> So really, the problem isn't with the sessions or really the db
> (inserts are atomic). A multi field key should be used to isolate the
> row for examination on repeated request. Since the whole point is to
> avoid multiple entries (submits).
>
> Set up the schema so that the key relies on at least two fields, say
> the username/unique id (random for each session) and the item/doc name
> (as gathered from the form.)
>
> now apply the logic:
>
> INSERT INTO <table> VALUES('$unique_id','$itemname',?,?,?)... ON
> DUPLICATE KEY UPDATE unique_id = '$unique_id'
>
> returns 1 on INSERT and 2 on UPDATE...
>
> so that extra clicks on the submit button don't add extra entries of the
> same item, and user can be warned about adding an item with the same
> name during the same session (ie: do you want to edit this item?)
>
>
>
> Norm
>


Even that has problems. Again, take a forum - what happens if a user
wants to respond with "lol" to two different posts? And we don't know
if there is an item name/doc name. Plus you're getting into a real mess
of code to maintain.

The bottom line is - there is no absolute way to keep from having
duplicate entries. Every way has potential holes.

But the best way is to prevent the duplicate from being submitted in the
first place.

--
==================
Remove the