-
Notifications
You must be signed in to change notification settings - Fork 27
Description
First off, eaio-uuid could possibly be the best Java UUID library out there. That said, I found a couple of somewhat related issues with it for my usecase:
Background: I have bunch of event streams that I need to migrate from one database to another. Each stream consists of events with auto increment IDs:
- 1: timestamp_1, data_1
- 2: timestamp_2, data_2
- ...
- n: timestamp_n, data_n
Since the new storage solution is more a distributed one I intend to migrate the auto increment IDs to UUIDs. The end goal will be:
- UUID1(timestamp_1): data_1
- UUID1(timestamp_2): data_2
- ...
- UUID1(timestamp_n): data_n
To be able to generate these UUIDs I had a look at UUIDGen#createTime(...) which at first looked like a perfect fit. However;
Problem: The UUIDGen#createTime(...) implementation only works for correctly for ascending consecutive input of currentTimeMillis. As soon as a descending currentTimeMillis is put in, the next time generated will be increased by 100 nanoseconds. That is a bug.
In my case this means that I need to sort all my events globally by timestamp to correctly generate UUIDs of type 1. Since my data is too big for a single instance to handle, this is impossible. Restarting the JVM for every stream :-) is neither an option.
While UUIDGen#createTime(...) is thread-safe per se (it uses AtomicLong for synchronization), a related problem is that of multiple threads calling UUIDGen#createTime(...). Since they generally will have a different notion of time (especially in my case where time is not Thread.currentTimeMillis()) the implementation is inherently broken. This boils down to singleton state;
If it wasn't for the fact that lastTime and UUIDGen#createTime(...) were static, this would not be a problem. In that case, I'd be able to instantiate one UUIDGen per migration thread, sorting my stream individually and then generating UUID using strictly monotonical input to UUIDGen#createTime(...).
Proposed solution:
- Make a non-static implementation of
UUIDGen, call itReusableUUIDGenor something, that supports reuse with non-singleton state. - Make the current
UUIDGensimply hold a singletonReusableUUIDGeninstance and proxy calls to it. - Patch
UUIDGen#createTime(...)theifstatement in thewhileloop to properly support decreasing input to the method. - Document the fact that
UUIDGen#createTime(...)only works for consecutive larger input.
The above solution has the benefit of being a backward compatible implementation while still enabling reusing the UUIDGen.
Workaround:
- For the descending issue, the caller could make a
UUIDGen#createTime(0)call before calling the static method with a descending value. - For the issue of global state, all input currently need to be strictly monotonically increasing.
Related:
- Possibly Implementation of the time-based UUID #3.