Attaching derby-712-05-af-sequenceGenerator.diff. This patch adds cached sequence generators to the data dictionary and makes the NEXT VALUE FOR clause yield the expected results. Regression tests have passed for me but I am re-running them just to be safe.
User-visible behavior changes as follows:
A) When you issue a NEXT VALUE FOR clause, the value of the sequence generator really advances as expected.
B) If you shutdown the database after using a sequence generator, the generator may leak up to 5 values. That is, when you reboot, the next value for the generator may be up to 5 steps beyond what you expected.
Here is the approach I adopted:
1) SequenceGenerator - This is a general class which manages ranges of sequence values. It advances a counter and hands out the next sequence value in a range. In addition, it calculates chunk sizes for sub-ranges which can be pre-allocated. Right now, pre-allocation is pretty dumb: we just pre-allocate 5 numbers at a time. In the future we could do something fancier. For instance, we could give the user a property for tuning the size of pre-allocated ranges, or Derby could auto-tune this number itself based on run-time behavior.
2) SequenceUpdater - This is an abstract class. It is a Cacheable to be stored in the data dictionary. Concrete subclasses are responsible for particular types of sequences. For instance, there is an inner subclass which is responsible for ANSI/ISO sequence generators. In the future, we could add another inner subclass which is responsible for identity columns. There is also a testing subclass which I used to test boundary conditions related to the currently unimplemented optional clauses of the CREATE SEQUENCE statement. The SequenceUpdater does the following tasks:
a) It calls its corresponding SequenceGenerator to calculate the next value in a sequence.
b) It manages the updating of the system tables when a pre-allocated range needs to be recorded on disk.
c) It reclaims unused pre-allocated values when the data dictionary caches have to be flushed. This prevents us from leaking values when DDL is performed. In the future, similar reclamation could be performed during the orderly shutdown of a database. This probably requires some discussion.
There are some tricky bits in the implementation:
i) There are a couple synchronized methods in SequenceGenerator. It is my hope that these critical sections are short.
ii) The on-disk catalog value (in this case, SYS.SYSSEQUENCES.CURRENTVALUE) is updated in a read/write subtransaction of the session's execution transaction if possible--and that subtransaction is then immediately committed. However, if it is not possible to obtain an immediate lock on the catalog row, we fall back to updating the row in the parent transaction, that is, in the session's execution transaction. This is similar to what is done for identity columns today.
iii) Updating the value in the catalog row is managed by a little hopping back and forth among the DataDictionary, the SequenceUpdater, and the SequenceGenerator. Here's what the flow of control looks like:
o An Activation asks the DataDictionary for the next value in a sequence.
o The DataDictionary forwards the request to the SequenceUpdater.
o The SequenceUpdater forwards the request to the SequenceGenerator.
o If the SequenceGenerator determines that a new range needs to be allocated, it calculates the new endpoint of the range. Then the SequenceGenerator asks the SequenceUpdater to allocate the new range.
o The SequenceUpdater forwards that request to the DataDictionary.
o The DataDictionary updates the catalog row.
o Everyone returns and the Activation gets the value it asked for.
Touches the following files:
The SequenceGenerator described in (1) above.
The SequenceUpdater described in (2) above.
DataDictionary support for cached sequence generators.
A null in SYS.SYSSEQUENCES.CURRENTVALUE now means that a non-cycling sequence generator is exhausted. That is, it has run through its range of legal values.
New error message for exhausted sequence generators.
Code-generation for the NEXT VALUE FOR clause.
Run-time support for the NEXT VALUE FOR clause.
Regression tests for cached sequence generators. SGVetter is a re-implementation of sequence generation used to test the correctness of the production SequenceGenerator. SGVetter is less efficient than SequenceGenerator but it is easier to reason about its correctness.