package net.sinofool.dbpool.config;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Pattern;
import net.sinofool.dbpool.DBPool;
public class DBInstance {
private Random random = new Random(System.currentTimeMillis());
private ArrayList<DBServer> servers = new ArrayList<DBServer>();
private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private int access(String acc) {
// TODO needs more
if (acc.equalsIgnoreCase("rw")) {
return DBPool.WRITE_ACCESS | DBPool.READ_ACCESS;
}
if (acc.equalsIgnoreCase("r")) {
return DBPool.READ_ACCESS;
}
if (acc.equalsIgnoreCase("w")) {
return DBPool.WRITE_ACCESS;
}
return 0;
}
private String driver(String type) {
if (type.equals("mysql")) {
return "com.mysql.jdbc.Driver";
}
return type;
}
public List<DBServer> reloadConfig(net.sinofool.dbpool.idl.DBServer[] sers) {
ArrayList<DBServer> newServers = new ArrayList<DBServer>();
for (net.sinofool.dbpool.idl.DBServer ser : sers) {
DBServer dbs = new DBServer();
dbs.driver = driver(ser.type);
dbs.host = ser.host;
dbs.port = ser.port;
dbs.db = ser.db;
dbs.user = ser.user;
dbs.pass = ser.pass;
dbs.coreSize = ser.coreSize;
dbs.maxSize = ser.maxSize;
dbs.idleTimeSeconds = ser.idleTimeSeconds;
dbs.expression = ser.expression;
dbs.weight = ser.weight;
dbs.access = access(ser.access);
newServers.add(dbs);
}
// TODO need better alg to get changes
ArrayList<DBServer> changes;
rwLock.writeLock().lock();
try {
if (servers.size() != newServers.size()) {
changes = servers;
return changes;
}
changes = new ArrayList<DBServer>();
for (int i = 0; i < servers.size(); ++i) {
String oldChecksum = servers.get(i).checksum();
String newChecksum = newServers.get(i).checksum();
if (!oldChecksum.equals(newChecksum)) {
changes.add(servers.get(i));
}
}
} finally {
servers = newServers;
rwLock.writeLock().unlock();
}
return changes;
}
private int getDBServerList(int access, List<DBServer> candidate) {
int totalWeight = 0;
rwLock.readLock().lock();
for (DBServer entry : servers) {
if ((entry.access & access) == 0) {
continue;
}
candidate.add(entry);
totalWeight += entry.weight;
}
rwLock.readLock().unlock();
return totalWeight;
}
private int getDBServerList(int access, String pattern, List<DBServer> candidate) {
int totalWeight = 0;
Pattern objPattern = Pattern.compile(pattern);
rwLock.readLock().lock();
for (DBServer entry : servers) {
if ((entry.access & access) == 0) {
continue;
}
if (!objPattern.matcher(entry.expression).find()) {
continue;
}
candidate.add(entry);
totalWeight += entry.weight;
}
rwLock.readLock().unlock();
return totalWeight;
}
public DBServer getDBServer(int access, String pattern) {
LinkedList<DBServer> candidate = new LinkedList<DBServer>();
int totalWeight = 0;
if (pattern != null && !pattern.isEmpty()) {
totalWeight = getDBServerList(access, pattern, candidate);
} else {
totalWeight = getDBServerList(access, candidate);
}
if (totalWeight == 0) {
return null;
}
// TODO: need better weight alg
int randWeight = random.nextInt(totalWeight);
DBServer choosen = null;
for (DBServer dbServer : candidate) {
randWeight -= dbServer.weight;
if (randWeight <= 0) {
choosen = dbServer;
break;
}
}
return choosen;
}
}