Bug in method getShardIdForObject of ShardedSessionImpl

Description

This method seems to incorrectly throw an exception if your not using the ShardEncodingIdentifierGenerator to generate ID's for your entities. In my project the Shard ID's are created externally by a NoSql database system and then the data is shard into MySQL for long term storage. All works good when saving the object first time (new) but when trying to update, merge, saveOrUpdate it throws the exception "HibernateException("Can not use virtual sharding with non-shard resolving id gen")" below.

<code>
public ShardId getShardIdForObject(Object obj, List<Shard> shardsToConsider) {
1503 // TODO(maxr)
1504 // Also, wouldn't it be faster to first see if there's just a single shard
1505 // id mapped to the shard?
1506 Shard shard = getShardForObject(obj, shardsToConsider);
1507 if(shard == null) {
1508 return null;
1509 } else if (shard.getShardIds().size() == 1) {
1510 return shard.getShardIds().iterator().next();
1511 } else {
1512 String className;
1513 if (obj instanceof HibernateProxy) {
1514 className = ((HibernateProxy)obj).getHibernateLazyInitializer().getPersistentClass().getName();
1515 } else {
1516 className = obj.getClass().getName();
1517 }
1518 IdentifierGenerator idGenerator = shard.getSessionFactoryImplementor().getIdentifierGenerator(className);
1519 if (idGenerator instanceof ShardEncodingIdentifierGenerator) {
1520 return ((ShardEncodingIdentifierGenerator)idGenerator).extractShardId(getIdentifier(obj));
1521 } else {
1522 // TODO(tomislav): also use shard resolution strategy if it returns only 1 shard; throw this error in config instead of here
1523 throw new HibernateException("Can not use virtual sharding with non-shard resolving id gen");
1524 }
1525 }
1526 }
</code>

The fix which I have implemented in my own version of Hibernate Shards. is to change as below. I just return the first shard found in the list because we really don't care which shard the data is on we just need one/any to satisfy our operation or query. In my code I shard on the key and always end up with just one shardId returned from the selectShardIdsFromShardResolutionStrategyData method.

<code>
public ShardId getShardIdForObject(Object obj, List<Shard> shardsToConsider) {
// TODO(maxr) optimize this by keeping an identity map of objects to shardId
Shard shard = getShardForObject(obj, shardsToConsider);
if(shard == null) {
return null;
} else if (shard.getShardIds().size() == 1) {
return shard.getShardIds().iterator().next();
} else {
String className;
if (obj instanceof HibernateProxy) {
className = ((HibernateProxy)obj).getHibernateLazyInitializer().getPersistentClass().getName();
} else {
className = obj.getClass().getName();
}
IdentifierGenerator idGenerator = shard.getSessionFactoryImplementor().getIdentifierGenerator(className);
if (idGenerator instanceof ShardEncodingIdentifierGenerator) {
return ((ShardEncodingIdentifierGenerator)idGenerator).extractShardId(getIdentifier(obj));
} else {
List<ShardId> shardIds = selectShardIdsFromShardResolutionStrategyData(new
ShardResolutionStrategyDataImpl(obj.getClass(), getIdentifier(obj)));
if (shardIds!=null && shardIds.size() > 0) {
return shardIds.get(0);
}
throw new HibernateException("Can not resolve shard id using virtual sharding");
}
}
}
</code>

Environment

MySQL, hibernate 3.2, Java, unix

Status

Assignee

Max Ross

Reporter

Joe Hopkins

Labels

Feedback Requested

None

Feedback Requested By

None

backPortable

None

Suitable for new contributors

None

Pull Request

None

backportDecision

None

backportReEvaluate

None

Components

Affects versions

Priority

Major
Configure