• Post Reply Bookmark Topic Watch Topic
  • New Topic

Ensuring unique usernames efficiently?  RSS feed

 
Pojahn Moradi
Greenhorn
Posts: 10
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
For my project, a unique user can register an entity(unimportant) which a he or she owns. Here is the flow of the backend code:

1. Checks if user name exist. If not, jump to stage 3.
2. Compare if the supplied user name & password match with the data stored in the database.
3. Create the user if not exist.

If everything was single threaded, this would work fine. But since it's not, this wont. A thread for example can pass step 1, and before it has a chance to save an other thread passes that stage as well. Result: a duplicate entry!

Now to my questions:
- Since the chance of duplicate entry is utterly tiny, do I really need to handle this?
- If so, what is the best strategy? The current implementation is a locking mechanism, where you lock a user name during the steps above. This means other threads wanting to operate on the same username will block until a lock can be grabbed.
The blocking technique is however unpleasant due to the performance penalty. Are there better ways?
 
Winston Gutkowski
Bartender
Posts: 10573
65
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Pojahn Moradi wrote:Here is the flow of the backend code:
1. Checks if user name exist. If not, jump to stage 3.
2. Compare if the supplied user name & password match with the data stored in the database.
3. Create the user if not exist.

Well that sounds wrong right there. What if they simply mis-type their username? In that scenario, they'd get a new user created with the wrong name.

Far better:
1. Ask the user if they are a new user.
2. If they say yes, go to a "New User" function.
3. Otherwise, go to a login function.

Now in the login function, all you have to do is (a) check that the username they entered exists, and (b) the password is correct for that user.

In the New User function, all you have to do is check that the username doesn't exist; and the easiest way to do that is to INSERT the details into your user table once you have them all. If that fails, then obviously the name is already taken, so then you can ask them to enter another one and try the insert again ... and you just keep doing that until it succeeds.

In each case it's just a single action: either a SELECT (for a login) or an INSERT (for a new user), and you shouldn't need any locking whatsoever.

HIH

Winston
 
Campbell Ritchie
Sheriff
Posts: 53779
128
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You can always make the insert and select transactions and that will do all the locking you require, surely.
 
Winston Gutkowski
Bartender
Posts: 10573
65
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Campbell Ritchie wrote:You can always make the insert and select transactions and that will do all the locking you require, surely.

No real need, since they're both "atomic".

The problem with Pojahn's solution (as I see it) was that he was trying to
(a) Combine logging in with adding a new user.
(b) "Reserve" a 'new' name until the user has entered all their details properly; and that IS tricky to do without locking - particularly if your idiot user decides to go to lunch in the middle of entering their details.

It can be done, but the easiest solution (at least that I've found) is to reverse the "normal" order of the input process for a new user:
1. Enter all your details.
2. Then choose a username and password.
3. Press 'Create new user'.
Assuming you've done your job properly (and the database is up and running) the only reason that an INSERT should fail at that point is because the name has already been taken; in which case you just keep forcing them to change the name until the INSERT succeeds.

And once it does, you can simply hand off the same credentials you just entered to a login function (which doesn't even need to be visible), sure in the knowledge that it'll work.

Winston
 
Pojahn Moradi
Greenhorn
Posts: 10
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi!! Sorry for disappearing. The page have to be very simple, thus no login function. You pass username and password along with your entity(which is a string).
I added a locking mechanism, where each request locks the username. So the overhead will be minimal. Grabbing a lock is very trivial.
 
Winston Gutkowski
Bartender
Posts: 10573
65
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Pojahn Moradi wrote:The page have to be very simple, thus no login function. You pass username and password along with your entity(which is a string).
I added a locking mechanism, where each request locks the username. So the overhead will be minimal. Grabbing a lock is very trivial.

It may be very trivial, but the problem with it is precisely what you outlined in your first post - everyone else is locked out while someone is entering their details.

And simplicity is relative. You're causing yourself a pile of complexity in terms of back-end locking/exclusion/verification etc, just to have a simple screen - and that's no way to design a system.

You also haven't answered my very first point: What if somebody types their username in WRONG?

I say again: If I was doing this, I'd have two functions (or screens): a login one, and a new user one; and either one can be as simple or as complex as you want to make it.

Winston
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!