If by ‘parallel writes’ you mean a multi-record transaction, you can’t do that. It’s worth reading the section of the docs titled ‘Architecture - How it Works’, from the Architecture Overview onward.
You can check if a record with that email exists in the reverse lookup (useremails). First, attempt to create an entry in the reverse lookup (‘usersemails’) for the user record that doesn’t yet exist with a CREATE_ONLY RecordExistsPolicy. Think of it as a form of cooperative locking. If you’re able to create a record in the reverse lookup set with key email and value username this means you can now proceed to create a record in the ‘users’ set with key username. No other process in your application should be allowed to do so, by application logic, since they don’t have the agreed upon lock. If you follow this approach, uniqueness will be maintained, even without a multi-record transaction, since you shouldn’t create a record in ‘users’ if you can’t create the corresponding record in ‘usersemails’ first. The first client to it, gets to ensure a unique pair of records.
Parallel insertions happen across different keys, never of the same specific key. Every modification to a record locks it first, so while Aerospike is multi-node, multi-core, multi-threaded, and does lots of reads and writes in parallel, a record with a specific key cannot be modified at the same time by different clients.
If you’re using Aerospike Enterprise Edition, the reverse lookup and users sets should live in a namespace that is configured for strong consistency.
Let’s deal with the system you have, not a fictional one. UDFs cannot act on multiple records. Even in an RDBMS, you’d do this in a multi record transcation, using native SQL, not using a UDF (Pl/SQL or whatnot).