/* * @(#)ShardedSqlSessionFactoryImpl.java 2012-8-1 下午10:00:00 * * Copyright (c) 2011-2012 Makersoft.org all rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * */ package org.makersoft.shards.session.impl; import java.sql.Connection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.TransactionIsolationLevel; import org.makersoft.shards.ShardId; import org.makersoft.shards.cfg.MyBatisConfigurationsWrapper; import org.makersoft.shards.id.IdGenerator; import org.makersoft.shards.session.ShardedSqlSession; import org.makersoft.shards.session.ShardedSqlSessionFactory; import org.makersoft.shards.strategy.ShardStrategy; import org.makersoft.shards.strategy.ShardStrategyFactory; import org.makersoft.shards.utils.Assert; import org.makersoft.shards.utils.Iterables; import org.makersoft.shards.utils.Lists; import org.makersoft.shards.utils.Maps; import org.makersoft.shards.utils.Sets; /** * */ public class ShardedSqlSessionFactoryImpl implements ShardedSqlSessionFactory { private final Log log = LogFactory.getLog(getClass()); // the id of the control shard private static final int CONTROL_SHARD_ID = 0; private final List<SqlSessionFactory> sqlSessionFactories; private final List<ShardId> shardIds; // map of SessionFactories used by this ShardedSessionFactory (might be a subset of all SessionFactories) private final Map<SqlSessionFactory, Set<ShardId>> sqlSessionFactoryShardIdMap; // map of all existing SessionFactories, used when creating a new ShardedSessionFactory for some subset of shards @SuppressWarnings("unused") private final Map<SqlSessionFactory, Set<ShardId>> fullSqlSessionFactoryShardIdMap; private final ShardStrategy shardStrategy; private final IdGenerator idGenerator; // Reference to the SessionFactory we use for functionality that expects // data to live in a single, well-known location (like distributed sequences) private final SqlSessionFactory controlSqlSessionFactory; private final ShardedSqlSession singleShardedSqlSession; private final Configuration configurationsWrapper; public ShardedSqlSessionFactoryImpl( Map<SqlSessionFactory, Set<ShardId>> sessionFactoryShardIdMap, ShardStrategyFactory shardStrategyFactory, IdGenerator idGenerator) { this.sqlSessionFactories = Lists.newArrayList(sessionFactoryShardIdMap.keySet()); this.sqlSessionFactoryShardIdMap = Maps.newHashMap(); this.fullSqlSessionFactoryShardIdMap = sessionFactoryShardIdMap; this.shardIds = Lists.newArrayList(Iterables.concat(sessionFactoryShardIdMap.values())); Set<ShardId> uniqueShardIds = Sets.newHashSet(); SqlSessionFactory controlSqlSessionFactoryToSet = null; for (Map.Entry<SqlSessionFactory, Set<ShardId>> entry : sessionFactoryShardIdMap.entrySet()) { SqlSessionFactory implementor = entry.getKey(); Assert.notNull(implementor); Set<ShardId> shardIdSet = entry.getValue(); Assert.notNull(shardIdSet); Assert.notNull(!shardIdSet.isEmpty()); for (ShardId shardId : shardIdSet) { // TODO(tomislav): we should change it so we specify control shard in configuration if (shardId.getId() == CONTROL_SHARD_ID) { controlSqlSessionFactoryToSet = implementor; } if(!uniqueShardIds.add(shardId)) { final String msg = String.format("Cannot have more than one shard with shard id %d.", shardId.getId()); log.error(msg); throw new RuntimeException(msg); } if (shardIds.contains(shardId)) { if (!this.sqlSessionFactoryShardIdMap.containsKey(implementor)) { this.sqlSessionFactoryShardIdMap.put(implementor, Sets.<ShardId>newHashSet()); } this.sqlSessionFactoryShardIdMap.get(implementor).add(shardId); } } } this.controlSqlSessionFactory = controlSqlSessionFactoryToSet; this.shardStrategy = shardStrategyFactory.newShardStrategy(shardIds); this.idGenerator = idGenerator; this.singleShardedSqlSession = new ShardedSqlSessionImpl(this, shardStrategy); this.configurationsWrapper = new MyBatisConfigurationsWrapper(getAnyFactory().getConfiguration(), this.getSqlSessionFactories()); } private SqlSessionFactory getAnyFactory() { return sqlSessionFactories.get(0); } @Override public List<SqlSessionFactory> getSqlSessionFactories() { return Collections.<SqlSessionFactory> unmodifiableList(sqlSessionFactories); } @Override public ShardedSqlSessionFactory getSqlSessionFactory( List<ShardId> shardIds, ShardStrategyFactory shardStrategyFactory) { throw new UnsupportedOperationException(); } public SqlSession openControlSession() { Assert.notNull(controlSqlSessionFactory); SqlSession session = controlSqlSessionFactory.openSession(); return session; } @Override public ShardedSqlSession openSession() { return this.openSession(false); } @Override public ShardedSqlSession openSession(boolean autoCommit) { return this.openSession(ExecutorType.SIMPLE, autoCommit); } @Override public ShardedSqlSession openSession(ExecutorType execType) { return this.openSession(execType, false); } @Override public ShardedSqlSession openSession(ExecutorType execType, boolean autoCommit) { return singleShardedSqlSession; } @Override public ShardedSqlSession openSession(TransactionIsolationLevel level) { return this.openSession(ExecutorType.SIMPLE, level); } @Override public ShardedSqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) { return singleShardedSqlSession; } @Override public ShardedSqlSession openSession(Connection connection) { throw new UnsupportedOperationException( "Cannot open a sharded session with a user provided connection."); } @Override public ShardedSqlSession openSession(ExecutorType execType, Connection connection) { throw new UnsupportedOperationException( "Cannot open a sharded session with a user provided connection."); } @Override public Configuration getConfiguration() { return configurationsWrapper; } @Override public IdGenerator getIdGenerator() { return idGenerator; } @Override public Map<SqlSessionFactory, Set<ShardId>> getSqlSessionFactoryShardIdMap() { return sqlSessionFactoryShardIdMap; } }