I'll add something under the JCS util package. The utility I'm using looks like this:
/** * This handles dividing puts and gets. * <p> * There are two required properties. * <p> * <ol> * <li>.numberOfPartitions</li> * <li>.partitionRegionNamePrefix</li> * </ol> * System properties will override values in the properties file. * <p> * We use a JCS region name for each partition that looks like this: partitionRegionNamePrefix + "_" * + patitionNuber. The number is ) indexed based. * <p> * @author Aaron Smuts */ public class PartitionedJCSCacheImpl extends AbstractPropertyContainer implements Cache { /** the logger. */ private static final Log log = LogFactory.getLog( PartitionedJCSCacheImpl.class ); /** The number of partitions. */ private int numberOfPartitions = 1; /** * We use a JCS region name for each partition that looks like this: partitionRegionNamePrefix + * "_" + partitionNumber */ private String partitionRegionNamePrefix; /** An array of partitions built during inialization. */ private JCS[] partitions; /** Is the class initialized. */ private boolean initialized = false; /** Sets default properties heading and group. */ public PartitionedJCSCacheImpl() { setPropertiesHeading( "PartitionedJCSCache" ); setPropertiesGroup( "webservices" ); } /** * Puts the value into the appropriate cache partition. * <p> * @param key key * @param object object * @return true if there were no errors. * @throws ConfigurationException on configuration problem */ public boolean put( Serializable key, Serializable object ) throws ConfigurationException { if ( key == null || object == null ) { log.warn( "Bad input key [" + key + "]. Cannot put null into the cache." ); return false; } ensureInit(); int partition = getPartitionNumberForKey( key ); try { partitions[partition].put( key, object ); return true; } catch ( CacheException e ) { log.error( "Problem putting value for key [" + key + "] in cache [" + partitions[partition] + "]" ); return false; } } /** * Gets the object for the key from the desired partition. * <p> * @param key key * @return result, null if not found. * @throws ConfigurationException on configuration problem */ public Object get( Serializable key ) throws ConfigurationException { if ( key == null ) { log.warn( "Bad input key [" + key + "]." ); return null; } ensureInit(); int partition = getPartitionNumberForKey( key ); return partitions[partition].get( key ); } /** * Gets the ICacheElement (the wrapped object) for the key from the desired partition. * <p> * @param key key * @return result, null if not found. * @throws ConfigurationException on configuration problem */ public ICacheElement getCacheElement( Serializable key ) throws ConfigurationException { if ( key == null ) { log.warn( "Bad input key [" + key + "]." ); return null; } ensureInit(); int partition = getPartitionNumberForKey( key ); return partitions[partition].getCacheElement( key ); } /** * This expects a numeric key. If the key cannot be converted into a number, we wil return 0. * TODO we could md5 it or get the hashcode. * <p> * We determine the partition by taking the mod of the number of partions. * <p> * @param key key * @return the partition number. */ protected int getPartitionNumberForKey( Serializable key ) { if ( key == null ) { return 0; } long keyNum = getNumericValueForKey( key ); int partition = (int) ( keyNum % getNumberOfPartitions() ); if ( log.isDebugEnabled() ) { log.debug( "Using partition [" + partition + "] for key [" + key + "]" ); } return partition; } /** * This can be overridden for special purposes. * <p> * @param key key * @return long */ public long getNumericValueForKey( Serializable key ) { String keyString = key.toString(); long keyNum = -1; try { keyNum = Long.parseLong( keyString ); } catch ( NumberFormatException e ) { // THIS IS UGLY, but I can't think of a better failsafe right now. keyNum = key.hashCode(); log.warn( "Counldn't convert [" + key + "] into a number. Will use hashcode [" + keyNum + "]" ); } return keyNum; } /** * Initialize if we haven't already. * <p> * @throws ConfigurationException on configuration problem */ protected synchronized void ensureInit() throws ConfigurationException { if ( !initialized ) { initialize(); } } /** * Use the partion prefix and the number of partions to get JCS regions. * <p> * @throws ConfigurationException on configuration problem */ protected synchronized void initialize() throws ConfigurationException { ensureProperties(); JCS[] tempPartitions = new JCS[this.getNumberOfPartitions()]; for ( int i = 0; i < this.getNumberOfPartitions(); i++ ) { String regionName = this.getPartitionRegionNamePrefix() + "_" + i; try { tempPartitions[i] = JCS.getInstance( regionName ); } catch ( CacheException e ) { log.error( "Problem getting cache for region [" + regionName + "]" ); } } partitions = tempPartitions; initialized = true; } /** * Loads in the needed configuration settings. System properties are checked first. A system * property will override local property value. * <p> * Loads the following JCS Cache specific properties: * <ul> * <li>heading.numberOfPartitions</li> * <li>heading.partitionRegionNamePrefix</li> * </ul> * @throws ConfigurationException on configuration problem */ protected void handleProperties() throws ConfigurationException { // Number of Partitions. String numberOfPartitionsPropertyName = this.getPropertiesHeading() + ".numberOfPartitions"; String numberOfPartitionsPropertyValue = getPropertyForName( numberOfPartitionsPropertyName, true ); try { this.setNumberOfPartitions( Integer.parseInt( numberOfPartitionsPropertyValue ) ); } catch ( NumberFormatException e ) { String message = "Could not convert [" + numberOfPartitionsPropertyValue + "] into a number for [" + numberOfPartitionsPropertyName + "]"; log.error( message ); throw new ConfigurationException( message ); } // Partition Name Prefix. String prefixPropertyName = this.getPropertiesHeading() + ".partitionRegionNamePrefix"; String prefix = getPropertyForName( prefixPropertyName, true ); this.setPartitionRegionNamePrefix( prefix ); } /** * Checks the system properties before the properties. * <p> * @param propertyName name * @param required is it required? * @return the property value if one is found * @throws ConfigurationException thrown if it is required and not found. */ protected String getPropertyForName( String propertyName, boolean required ) throws ConfigurationException { String propertyValue = null; propertyValue = System.getProperty( propertyName ); if ( propertyValue != null ) { if ( log.isInfoEnabled() ) { log.info( "Found system property override: Name [" + propertyName + "] Value [" + propertyValue + "]" ); } } else { propertyValue = this.getProperties().getProperty( propertyName ); if ( required && propertyValue == null ) { String message = "Could not find required property [" + propertyName + "] in propertiesGroup [" + this.getPropertiesGroup() + "]"; log.error( message ); throw new ConfigurationException( message ); } else { if ( log.isInfoEnabled() ) { log.info( "Name [" + propertyName + "] Value [" + propertyValue + "]" ); } } } return propertyValue; } /** * @param numberOfPartitions The numberOfPartitions to set. */ protected void setNumberOfPartitions( int numberOfPartitions ) { this.numberOfPartitions = numberOfPartitions; } /** * @return Returns the numberOfPartitions. */ protected int getNumberOfPartitions() { return numberOfPartitions; } /** * @param partitionRegionNamePrefix The partitionRegionNamePrefix to set. */ protected void setPartitionRegionNamePrefix( String partitionRegionNamePrefix ) { this.partitionRegionNamePrefix = partitionRegionNamePrefix; } /** * @return Returns the partitionRegionNamePrefix. */ protected String getPartitionRegionNamePrefix() { return partitionRegionNamePrefix; } /** * @param partitions The partitions to set. */ protected void setPartitions( JCS[] partitions ) { this.partitions = partitions; } /** * @return Returns the partitions. */ protected JCS[] getPartitions() { return partitions; } --- On Tue, 8/11/09, Aaron Smuts <asm...@yahoo.com> wrote: > From: Aaron Smuts <asm...@yahoo.com> > Subject: Re: JCS HA cluster, is possible? > To: "JCS Users List" <jcs-users@jakarta.apache.org>, "rcolme...@tiscali.it" > <rcolme...@tiscali.it> > Date: Tuesday, August 11, 2009, 10:54 AM > > You can implement this very easily with a bit of client > code. In fact, I've done just this elsewhere, or at > least something very similar. > > I have an installation that handles millions of items a > day. The items average 80k. I don't have disk > space to keep them all on any one box. So, I > partitioned the data. I did it this way. > > I took 8 boxes and setup 4 remote cache server > primary/failover pairs. (fyi. Each is configured to > use a jdbc disk cache backed by mysql running locally.) > > Every client is configured with 4 remote cache client > auxiliaries, one for each pair. > > I configured 4 regions on the clients. You could have > far more. > > I divided the remote clients between the regions. > Region 1 uses p/f pair A. Region 2, B . . . > > (In another instance I have 180 regions divided between 4 > remote servers.) > > I decide what region to put the data in through a simple > algorithm: key mod numerOfPartitions (here 4) = the > region. > > I named the regions in a pattern like this: > > MyPartitionedData_0 > MyPartitionedData_1 > MyPartitionedData_2 > MyPartitionedData_3 > > I take the suffic from the algorithm and put the data in > the appropriate region. I made a simple abstraction > that does just this. > > I could add more partitions and reconfigure. It can > be scaled indefinitely. . .. > > Perhaps I'll put in in the JCS util package. > > Cheers, > > Aaron > > > > --- On Tue, 8/11/09, rcolme...@tiscali.it > <rcolme...@tiscali.it> > wrote: > > > From: rcolme...@tiscali.it > <rcolme...@tiscali.it> > > Subject: JCS HA cluster, is possible? > > To: jcs-users@jakarta.apache.org > > Date: Tuesday, August 11, 2009, 10:40 AM > > Hi, > > > > I have a question about JCS behavior. > > > > Suppose this scenario: > > - > > four JCS server: S1,S2,S3,S4 > > - for every server a max of 10,000 > > cacheable objects > > - a client C1 > > > > I need that client C1 writes 40,000 > > objects to 4 JCS servers. JCS could automatic > balance > > the > > objects > > insertion between the 4 servers partitioning the > objects > > set (via round > > robin, for example)? > > > > I need the maximum performance (availability), > > not affordability. Substantially I need > > that an object instance "O1" > > is allocated _only_ in one server and that the client > > lookup > > is > > executed in parallel on the four servers. > > > > Is this possible with JCS? > > > > > > TIA > > Roberto Colmegna > > > > > > > > > > Torna a grande richiesta l'offerta estiva di Tiscali > Photo > > !! Non rinuniciare ai tuoi ricordi. Stampa le tue foto > a > > soli 0,09 euro > > > > > > > > http://photo.tiscali.it > > > > > --------------------------------------------------------------------- > > To unsubscribe, e-mail: jcs-users-unsubscr...@jakarta.apache.org > > For additional commands, e-mail: jcs-users-h...@jakarta.apache.org > > > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: jcs-users-unsubscr...@jakarta.apache.org > For additional commands, e-mail: jcs-users-h...@jakarta.apache.org > > --------------------------------------------------------------------- To unsubscribe, e-mail: jcs-users-unsubscr...@jakarta.apache.org For additional commands, e-mail: jcs-users-h...@jakarta.apache.org