9 Digits Unique ID through the day

java, uniqueidentifier

Solution

Nine digits to handle 1,000,000 IDs gives us three digits to play with (we need the other six for the 0-999999 for the ID).

I assume you have a multi-server setup. Assign each server a three-digit server ID, and then you can allocate unique ID values within each server without worrying about overlap between them. It can just be an ever-increasing value in memory, except to survive JVM restarts, we need to echo the most recently allocated value to disk (well, to anywhere you want to store it — local disk, memcache, whatever).

To ensure you don't hit the overhead of file/whatever I/O on each request, you allocate the IDs in blocks, echoing the endpoint of the block back to the storage.

So it ends up being:

- Give each server an ID

- Have storage on the server which stores the last allocated value for the day (a file, for instance)

- Have the ID allocator work in blocks (10 IDs at a time, 100, whatever)

- To allocate a block:

- Read the file, write back a number increased by your blocksize

- Use IDs from the block

- The ID would be , e.g. 12000000027 for the 28th ID allocated by server #12

- When the day changes (e.g., midnight), throw away your current block and allocate a new one for the new day

In pseudocode:

class IDAllocator {
    Storage storage;
    int     nextId;
    int     idCount;
    int     blockSize;
    long    lastIdTime;

    /**
     * Creates an IDAllocator with the given server ID, backing storage,
     * and block size.
     *
     * @param   serverId        the ID of the server (e.g., 12)
     * @param   s               the backing storage to use
     * @param   size            the block size to use
     * @throws  SomeException   if something goes wrong
     */
    IDAllocator(int serverId, Storage s, int size)
    throws SomeException {

        // Remember our info
        this.serverId = serverId * 1000000; // Add a million to make life easy
        this.storage = s;
        this.nextId = 0;
        this.idCount = 0;
        this.blockSize = bs;
        this.lastIdTime = this.getDayMilliseconds();

        // Get the first block. If you like and depending on
        // what container this code is running in, you could
        // spin this out to a separate thread.
        this.getBlock();
    }

    public synchronized int getNextId()
    throws SomeException {
        int id;

        // If we're out of IDs, or if the day has changed, get a new block
        if (idCount == 0 || this.lastIdTime < this.getDayMilliseconds()) {
            this.getBlock();
        }

        // Alloc from the block    
        id = this.nextId;
        --this.idCount;
        ++this.nextId;

        // If you wanted (and depending on what container this
        // code is running in), you could proactively retrieve
        // the next block here if you were getting low...

        // Return the ID
        return id + this.serverId;
    }

    protected long getDayMilliseconds() {
        return System.currentTimeMillis() % 86400000;
    }

    protected void getBlock()
    throws SomeException {
        int id;

        synchronized (this) {
            synchronized (this.storage.syncRoot()) {
                id = this.storage.readIntFromStorage();
                this.storage.writeIntToStroage(id + blocksize);
            }

            this.nextId = id;
            this.idCount = blocksize;
        }
    }
}

...but again, that's pseudocode, and you might want to throw some proactive stuff in there so you never block on I/O waiting for an ID when you need one.

The above is written assuming you already have some kind of application-wide singleton, and the `IDAllocator` instance would just be a data member in that single instance. If not, you could readily make the above a singleton instead, by giving it the classic `getInstance` method and having it read its configuration from the environment rather than receiving it as arguments to the constructor.

Problem

Having one puzzling requirement. Basically I need to create unique id with these criteria - 9 digits number, unique for the day (means it's ok if the number appears again the next day ) - generated in realtime ; java only ( means no sequence number generation from database -actually no database access at all ) - the number is generated to populate a requestID, and around 1.000.000 id will be generated per day. - UUID or UID should not be used ( more than 9 digits ) Here is my consideration : - using sequence number sounds good, but in case JVM restart, the requestId might be re-generated. - using time HHmmssSSS ( Hour Minute Second Milliseconds ) have 2 issues : a. System Hour might be changed by server admin. b. Can cause issue if 2 requests being asked on same milliseconds. Any idea?

Original source