I am designing a new AppEngine/Python HRD application. In this application, I need to ensure that each user that registers cannot use a name that has already been assigned to another user, and that if two users attempt to register with the same username at the exact same moment, that only one of them will be given the username.
If I were to put all usernames in a single entity group and use transactions to ensure uniqueness, then the writing of the username/object in a transaction could potentially slow down all registration processes. So this approach doesn't seem like a good idea.
Another option would be to use the username as the key, which has the disadvantage of possibly making it difficult for the user to later change their username.
What is the best/standard approach to achieve this in AppEngine?
App Engine allows up to 1 write per second within the same entity group. To surpass that barrier you have to have 60 x 60 x 24 = 86.4k registrations on the same day, which I think you can live with.
If you still think you need any faster process you could use sharding (more typically known for counters - https://developers.google.com/appengine/articles/sharding_counters), which is basically having different tables for users (or usernames) so that you can read them all to check for uniqueness (App Engine is good at doing many reads per second) and have as much better write pace as tables for usernames you add.
More of sharding on writes here - https://developers.google.com/appengine/articles/scaling/contention
Hope it helps.
Ok.
You don't need to stick all the usernames in a big entity group to guarantee consistency.
Make the username the Key of the datastore entity governing the login.
Then inside a transaction.
As an aside if you used email addresses then it would more than likely mean no clashes ever. and I am not sure why visible nick names need to be unique, but then you probably have a good reason.
Each actual user object can have a system generated unique id, (this is a separate entity to the login entity).
If you are really paranoid, then look at using memcache CAS operations to effectively act as a lock on the username key and prevent simultaneous operations, though I don't think it would be necessary.
Entities might look like
This means only a single get() is required to fetch a login, and second to get the rest of the user details but is much cheaper/faster than queries. It also means that the login name/code could be changed over time without disrupting the actual user entity if you really wanted such functionality. Or possibly support multiple login methods for a single user - ie facebook and twitter. It also means a login entity can be removed and login re-used by other people over time, and the user entity can stay if system integrity/history is required.