tags:

views:

114

answers:

2

If I start using a HiLo generator to assign ID's for a table, and then decide to increase or decrease the capacity (i.e. the maximum 'lo' value), will this cause collisions with the already-assigned ID's?

I'm just wondering if I need to put a big red flag around the number saying 'Don't ever change this!'

Note - not NHibernate specific, I'm just curious about the HiLo algorithm in general.

+1  A: 

Just by experience I'd say: yes, decreasing will cause collisions. When you have a lower max low, you get lower numbers, independent of the high value in the database (which is handled the same way, eg. increment with each session factory instance in case of NH).

There is a chance that increasing will not cause collisions. But you either need to try or ask someone who knows better then I do to be sure.

Stefan Steinegger
+2  A: 

HiLo algorithms in general basically map two integers to one integer ID. It guarantees that the pair of numbers will be unique per database. Typically, the next step is to guarantee that a unique pair of numbers maps to a unique integer ID.

A nice explanation of how HiLo conceptually works is given in this previous SO answer

Changing the max_lo will preserve the property that your pair of numbers will be unique. However, will it make sure that the mapped ID is unique and collision-free?

Let's look at Hibernate's implementation of HiLo. The algorithm they appear to use (as from what I've gathered) is: (and I might be off on a technicality)

h = high sequence (starting at 0)
l_size = size of low block
l = low sequence (starting at 1)

ID = h*l_size + l

So, if your low block is, say, 100, your reserved ID blocks would go 1-100, 101-200, 201-300, 301-400...

Your High sequence is now 3. Now what would happen if you all of a sudden changed your l_size to 10? Your next block, your High is incremented, and you'd get 4*10+1 = 41

Oops. This new value definitely falls within the "reserved block" of 1-100. Someone with a high sequence of 0 would think, "Well, I have the range 1-100 reserved just for me, so I'll just put down one at 41, because I know it's safe."

There is definitely a very, very high chance of collision when lowering your l_max.

What about the opposite case, raising it?

Back to our example, let's raise our l_size to 500, turning the next key into 4*500+1 = 2001, reserving the range 2001-2501.

It looks like collision will be avoided, in this particular implementation of HiLo, when raising your l_max.

Of course, you should do some own tests on your own to make sure that this is the actual implementation, or close to it. One way would be to set l_max to 100 and find the first few keys, then set it to 500 and find the next. If there is a huge jump like mentioned here, you might be safe.

However, I am not by any means suggesting that it is best practice to raise your l_max on an existing database.

Use your own discretion; the HiLo algorithm isn't exactly one made with varying l_max in mind, and your results may in the end be unpredictable depending on your exact implementation. Maybe someone who has had experience with raising their l_max and finding troubles can prove this count correct.

So in conclusion, even though, in theory, Hibernate's HiLo implementation will most likely avoid collisions when l_max is raised, it probably still isn't good practice. You should code as if l_max were not going to change over time.

But if you're feeling lucky...

Justin L.
Very thorough, thanks!
Jon M