You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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 it ReusableUUIDGen or something, that supports reuse with non-singleton state.
Make the current UUIDGen simply hold a singleton ReusableUUIDGen instance and proxy calls to it.
Patch UUIDGen#createTime(...) the if statement in the while loop 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.
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:
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:
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 ofcurrentTimeMillis
. As soon as a descendingcurrentTimeMillis
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 usesAtomicLong
for synchronization), a related problem is that of multiple threads callingUUIDGen#createTime(...)
. Since they generally will have a different notion of time (especially in my case where time is notThread.currentTimeMillis()
) the implementation is inherently broken. This boils down to singleton state;If it wasn't for the fact that
lastTime
andUUIDGen#createTime(...)
were static, this would not be a problem. In that case, I'd be able to instantiate oneUUIDGen
per migration thread, sorting my stream individually and then generating UUID using strictly monotonical input toUUIDGen#createTime(...)
.Proposed solution:
UUIDGen
, call itReusableUUIDGen
or something, that supports reuse with non-singleton state.UUIDGen
simply hold a singletonReusableUUIDGen
instance and proxy calls to it.UUIDGen#createTime(...)
theif
statement in thewhile
loop to properly support decreasing input to the method.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:
UUIDGen#createTime(0)
call before calling the static method with a descending value.Related:
The text was updated successfully, but these errors were encountered: