Fields Summary |
---|
private static final long | MAX_KEYSThe maximum number of keys that may be safely generated without
going to the database. You should lower this number for client
applications and other short-lived programs. The number can be
higher for applications with long uptimes. All applications
using the same sequencer, however, should have the same value
for MAX_KEYS . |
private static final HashMap | sequencersAll sequencers currently in memory. |
private String | nameThe name of this sequencer. |
private long | seedThe seed this sequencer will use for generating its ID's. |
private long | sequenceThe current sequence within this sequencer's seed. |
private static final String | CREATE_SEQThe SQL for creating a new sequence in the database. |
private static final int | INS_NAMEConstant for the name parameter. |
private static final int | INS_SEEDConstant for the seed parameter. |
private static final int | INS_UPDATEConstant for the lastUpdate parameter |
private static final String | DEFAULT_DSNThe name of a DSN to use if none is configured in the system
properties. |
private static final String | DSN_PROPThe name of the system property to check for a DSN. |
private static final String | FIND_SEQThe SQL for getting a seed for a sequence from the database. |
private static final int | SEL_NAMEConstant for the name parameter. |
private static final int | SEL_SEEDConstant for the seed column. |
private static final int | SEL_UPDATEConstant for the lastUpdate column. |
private static String | UPDATE_SEQThe SQL for incrementing the seed in the database. |
private static final int | UPD_SEEDConstant for the seed parameter. |
private static final int | UPD_SET_UPDATEConstant for the lastUpdate set parameter |
private static final int | UPD_NAMEConstant for the name parameter. |
private static final int | UPD_WHERE_UPDATEConstant for the lastUpdate parameter. |
Methods Summary |
---|
private void | create(java.sql.Connection conn)Creates a new entry in the database for this sequence. This method
will throw an error if two threads are simultaneously trying
to create a sequence. This state should never occur if you
go ahead and create the sequence in the database before
deploying the application. It could be avoided by checking
SQL exceptions for the proper XOPEN SQLState for duplicate
keys. Unfortunately, that approach is error prone due to the lack
of consistency in proper XOPEN SQLState reporting in JDBC drivers.
PreparedStatement stmt = null;
ResultSet rs = null;
try {
stmt = conn.prepareStatement(CREATE_SEQ);
stmt.setString(INS_NAME, name);
stmt.setLong(INS_SEED, 0L);
stmt.setLong(INS_UPDATE, System.currentTimeMillis());
if( stmt.executeUpdate() != 1 ) {
throw new SQLException("No row was inserted.");
}
seed = 0L;
}
finally {
if( rs != null ) {
try { rs.close(); }
catch( SQLException e ) { }
}
if( stmt != null ) {
try { stmt.close(); }
catch( SQLException e ) { }
}
}
|
public static final org.dasein.persist.Sequencer | getInstance(java.lang.String name)Looks to see if a sequencer has been generated for the sequence
with the specified name. If not, it will instantiate one.
Multiple calls to this method with the same name are guaranteed
to receive the same sequencer object. For best performance,
classes should save a reference to the sequencer once they get it
in order to avoid the overhead of a HashMap lookup.
synchronized( sequencers ) {
if( !sequencers.containsKey(name) ) {
Sequencer seq = new Sequencer(name);
sequencers.put(name, seq);
return seq;
}
else {
return (Sequencer)sequencers.get(name);
}
}
|
public synchronized long | next()Generates a new unique number. The unique number is based on the
following algorithm:
unique number = seed multiple by
maximum keys per seed added to seed sequence
The method then increments the seed sequence for the next
ID to be generated. If the ID to be generated would exhaust
the seed, then a new seed is retrieved from the database.
Connection conn = null;
// when seed is -1 or the keys for this seed are exhausted,
// get a new seed from the database
if( (seed == -1L) || ((sequence + 1) >= MAX_KEYS) ) {
try {
String dsn = System.getProperty(DSN_PROP, DEFAULT_DSN);
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup(dsn);
conn = ds.getConnection();
reseed(conn);
}
catch( SQLException e ) {
throw new PersistenceException(e);
}
catch( NamingException e ) {
throw new PersistenceException(e);
}
finally {
if( conn != null ) {
try { conn.close(); }
catch( SQLException e ) { }
}
}
}
// up the sequence value for the next key
sequence++;
// the next key for this sequencer
return ((seed * MAX_KEYS) + sequence);
|
private void | reseed(java.sql.Connection conn)Gets the next seed from the database for this sequence.
PreparedStatement stmt = null;
ResultSet rs = null;
try {
// Keep in this loop as long as we encounter concurrency errors
do {
stmt = conn.prepareStatement(FIND_SEQ);
stmt.setString(SEL_NAME, name);
rs = stmt.executeQuery();
if( !rs.next() ) {
// no such sequence, create it
{
// close resources
try { rs.close(); }
catch( SQLException e ) { }
rs = null;
try { stmt.close(); }
catch( SQLException e ) { }
stmt = null;
}
create(conn);
}
else {
long ts;
seed = rs.getLong(SEL_SEED) + 1L;
ts = rs.getLong(SEL_UPDATE);
{
// close resources
try { rs.close(); }
catch( SQLException e ) { }
rs = null;
try { stmt.close(); }
catch( SQLException e ) { }
stmt = null;
}
// increment the seed in the database
stmt = conn.prepareStatement(UPDATE_SEQ);
stmt.setLong(UPD_SEED, seed);
stmt.setLong(UPD_SET_UPDATE, System.currentTimeMillis());
stmt.setString(UPD_NAME, name);
stmt.setLong(UPD_WHERE_UPDATE, ts);
if( stmt.executeUpdate() != 1 ) {
// someone changed the database! try again!
seed = -1L;
}
}
} while( seed == -1L );
sequence = -1L;
}
finally {
if( rs != null ) {
try { rs.close(); }
catch( SQLException e ) { }
}
if( stmt != null ) {
try { stmt.close(); }
catch( SQLException e ) { }
}
}
|