-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: is this a generic clusterable id generator
PostPosted: Fri May 28, 2004 10:27 am 
JBoss jBPM Developer
JBoss jBPM Developer

Joined: Thu Aug 28, 2003 11:56 am
Posts: 30
Location: Belgium
Hi guys,

I have written something that I think is a generic clusterable id generator. It doesn't require your db to support locking and its all written in standard java (no j2ee dependancies).

I want to know
1) if you can spot a flaw in the ideas and principles of the mechanism
2) if you can spot a flaw in the implementation.
3) if I'm reinventing the wheel or not. maybe someone has already done it or maybe its already in the hibernate distro somewhere.

strategy : every node uses the sequence block pattern. for each node there is
a row in the database that keeps track of the next free sequence. the trick
is that each node only consumes a portion of the ids from the block it acquires.
each node consumes a different portion of the block.

every node is configered with its id and the total number of nodes in the
cluster.

e.g. 3 nodes, blocksize 100. Nodes are numbered 1, 2 and 3. The 3 rows in
the database look like this

Code:
NODE_ID | NEXT_FREE_ID
----------------------
1       | 1
2       | 1
3       | 1

Whenever a node needs a block of ids, it will request a block of 300 ids. for
the first blocks this results in node one using ids 1-100, node 2 will use ids
101-200 and node 3 will use 201-300.

Within a node I use static synchronization as a row-locking mechanism.


In the next code-fragment consider following equalities :
* PersistenceSessionFactory == hibernate SessionFactory
* PersistenceSession == hibernate Session

Code:
public class SequenceBlockIdGenerator implements IdGenerator {

  private static long nextId = 0;
  private static long lastId = -1;
 
  private PersistenceSessionFactory persistenceSessionFactory = null;
  private long nodeId = -1;
  private long totalNodes = -1;
  private long blockSize = -1;
 
  public SequenceBlockIdGenerator( JbpmConfiguration jbpmConfiguration ) {
    persistenceSessionFactory = jbpmConfiguration.getPersistenceSessionFactory();
    nodeId = jbpmConfiguration.getLong( "jbpm.id.generator.node.id" );
    totalNodes = jbpmConfiguration.getLong( "jbpm.id.generator.total.nodes" );
    blockSize = jbpmConfiguration.getLong( "jbpm.id.generator.block.size" );
  }
 
  public long getNextId() {
    return getNextId( persistenceSessionFactory, nodeId, totalNodes, blockSize );
  }
 
  public static synchronized long getNextId( PersistenceSessionFactory persistenceSessionFactory, long nodeId, long totalNodes, long blockSize ) {
    long generatedId = 0;

    // if there are no more ids available in the current block
    if ( lastId < nextId ) {

      // get a new block of ids
      log.debug("getting a new block of ids: " + nextId + ", " + lastId );
      PersistenceSession persistenceSession = persistenceSessionFactory.createPersistenceSession();
      persistenceSession.beginTransaction();

      // a SequenceBlock-object corresponds to one row in the sequence-table
      SequenceBlock sequenceBlock = null;
     
      try {
        sequenceBlock = (SequenceBlock) persistenceSession.load( SequenceBlock.class, new Long( nodeId ) );
      } catch (InvalidIdException e) {
        sequenceBlock = new SequenceBlock( new Long( nodeId ) );
      }
     
      // a block is reserved for all nodes in the cluster
      long firstIdOfCompleteBlock = sequenceBlock.getNextBlock(blockSize * totalNodes);

      // this node only consumes a part of the block   
      nextId = firstIdOfCompleteBlock + (blockSize * nodeId);
      lastId = nextId + blockSize - 1;

      persistenceSession.save( sequenceBlock );
      persistenceSession.commitTransaction();
      persistenceSession.close();

      log.debug("got a new block of ids: " + nextId + ", " + lastId );
    }

    // take the first available id
    generatedId = nextId++;
   
    return generatedId;
  }

  private static Log log = LogFactory.getLog(SequenceBlockIdGenerator.class);
}


Regards, Tom.


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 28, 2004 10:29 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Isn't this the same as Hi/Lo?

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject: i think its different
PostPosted: Fri May 28, 2004 11:03 am 
JBoss jBPM Developer
JBoss jBPM Developer

Joined: Thu Aug 28, 2003 11:56 am
Posts: 30
Location: Belgium
i've just checked the hibernate hilo implementations and i think they are different.

SequenceGenerator and SequenceHiLoGenerator use database sequences, which i don't want because thats a db-specific feature.

the implementation that comes closest is the TableHiLoGenerator, but that one uses database locking
Code:
...
public class TableGenerator ... {
  ...
  if ( dialect.supportsForUpdate() ) query += " for update";
  ...
}


what i have tried to do is replace the database locking by using a row for each node in the cluster and by using static java synchronization within one node (one classloader to be correct).

Regards, Tom.


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 28, 2004 3:23 pm 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
You still need database locking on node level, or won't you have any concurrent access to the database? (eg. just one thread always)


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 28, 2004 4:14 pm 
JBoss jBPM Developer
JBoss jBPM Developer

Joined: Thu Aug 28, 2003 11:56 am
Posts: 30
Location: Belgium
on a node level, I use java synchronization on a static method.

the only downside i found so far is that you have to determine the max number of nodes in the cluster upfront (=at configuration time). its no problem that not all nodes in the cluster are up and running. but increasing the total number (=max number) of nodes is difficult.

but still i think that disadvantage is less of a constraint then using db-specific or appserver specific features.

we're using hibernate in the jbpm.org project. we want to ship the jbpm.core.jar so that users do not have to modify the hibernate mappings inside, whatever the db or appserver they use.

Regards, Tom.


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 28, 2004 4:39 pm 
Newbie

Joined: Thu May 27, 2004 9:14 am
Posts: 11
That looks like it will work. Some guys here used that paradigm for an ejb project with composite ids.

Do you have to go that approach? Could you use UUIDs instead?

Much easier...


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.