rendered paste bodypublic class IdFactory
{
private static Logger _log = Logger.getLogger(IdFactory.class.getName());
private static final int STACK_SIZE_INCREMENT = 8196;
private AtomicInteger freeIdCount;
private AtomicInteger nextFreeId;
private static int newFreeID;
private static String[] id_updates =
{
"UPDATE items SET owner_id = ? WHERE owner_id = ?",
"UPDATE items SET object_id = ? WHERE object_id = ?",
"UPDATE character_quests SET char_id = ? WHERE char_id = ?",
"UPDATE character_recipebook SET char_id = ? WHERE char_id = ?",
"UPDATE character_shortcuts SET char_obj_id = ? WHERE char_obj_id = ?",
"UPDATE character_shortcuts SET shortcut_id = ? WHERE shortcut_id = ? AND type = 1", // items
"UPDATE character_macroses SET char_obj_id = ? WHERE char_obj_id = ?",
"UPDATE character_skills SET char_obj_id = ? WHERE char_obj_id = ?",
"UPDATE characters SET obj_Id = ? WHERE obj_Id = ?",
"UPDATE characters SET clanid = ? WHERE clanid = ?",
"UPDATE clan_data SET clan_id = ? WHERE clan_id = ?",
"UPDATE clan_data SET ally_id = ? WHERE ally_id = ?",
"UPDATE clan_data SET leader_id = ? WHERE leader_id = ?",
"UPDATE pets SET item_obj_id = ? WHERE item_obj_id = ?",
};
private static String[] id_checks =
{
"SELECT object_id FROM items WHERE object_id >= ? AND object_id < ?",
"SELECT owner_id FROM items WHERE object_id >= ? AND object_id < ?",
"SELECT char_id FROM character_quests WHERE char_id >= ? AND char_id < ?",
"SELECT char_id FROM character_recipebook WHERE char_id >= ? AND char_id < ?",
"SELECT char_obj_id FROM character_shortcuts WHERE char_obj_id >= ? AND char_obj_id < ?",
"SELECT char_obj_id FROM character_macroses WHERE char_obj_id >= ? AND char_obj_id < ?",
"SELECT char_obj_id FROM character_skills WHERE char_obj_id >= ? AND char_obj_id < ?",
"SELECT obj_Id FROM characters WHERE obj_Id >= ? AND obj_Id < ?",
"SELECT clanid FROM characters WHERE clanid >= ? AND clanid < ?",
"SELECT clan_id FROM clan_data WHERE clan_id >= ? AND clan_id < ?",
"SELECT ally_id FROM clan_data WHERE ally_id >= ? AND ally_id < ?",
"SELECT leader_id FROM clan_data WHERE leader_id >= ? AND leader_id < ?",
"SELECT item_obj_id FROM pets WHERE item_obj_id >= ? AND item_obj_id < ?",
};
private int _curOID;
private int _tempOID;
private int[] _freeOIDs;
private int _freeSize;
private Stack<Integer> _freeOIDStack = new Stack<Integer>();
private boolean initialized;
private static int FIRST_OID = 0x10000000;
private static int LAST_OID = 0x7FFFFFFF;
private static IdFactory _instance = new IdFactory();
private IdFactory()
{
if (Config.COMPACTION)
{
_curOID = FIRST_OID;
_tempOID = FIRST_OID;
_freeOIDs = new int[STACK_SIZE_INCREMENT];
_freeSize = 0;
java.sql.Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
//con.createStatement().execute("drop table if exists tmp_obj_id");
//create a temporary table
Statement s = con.createStatement();
try
{
s.executeUpdate("drop table temporaryObjectTable");
}
catch (SQLException e)
{
// TODO Auto-generated catch block
//e.printStackTrace();
}
s.executeUpdate("create table temporaryObjectTable" + " (object_id int NOT NULL PRIMARY KEY)");
s.executeUpdate("insert into temporaryObjectTable (object_id)" + " select obj_id from characters");
s.executeUpdate("insert into temporaryObjectTable (object_id)" + " select object_id from items");
s.executeUpdate("insert into temporaryObjectTable (object_id)" + " select clan_id from clan_data");
ResultSet result = s.executeQuery("select count(object_id) from temporaryObjectTable ORDER BY object_id");
result.next();
int size = result.getInt(1);
int[] tmp_obj_ids = new int[size];
// System.out.println("tmp table size: " + tmp_obj_ids.length);
result.close();
result = s.executeQuery("select object_id from temporaryObjectTable ORDER BY object_id");
int idx = 0;
while (result.next())
{
tmp_obj_ids[idx++] = result.getInt(1);
}
_curOID = tmp_obj_ids[size-1];
System.out.println("Max Id = " + _curOID);
result.close();
s.close();
int N = tmp_obj_ids.length;
for (idx = 0; idx < N; idx++)
{
//long time1 = System.currentTimeMillis();
N = insertUntil(tmp_obj_ids, idx, N, con);
// if (System.currentTimeMillis() - time1 > 0)
// System.out.println("T1: " + (System.currentTimeMillis() - time1));
}
_curOID++;
_log.config("IdFactory: Next usable Object ID is: " + _curOID);
initialized = true;
}
catch (Exception e1)
{
e1.printStackTrace();
_log.severe("ID Factory could not be initialized correctly:" + e1);
}
finally
{
try { con.close(); } catch (Exception e) {}
}
}
else
{
initialize();
_log.info("IDFactory: "+ freeIds.size() + " id's avaliable.");
}
//setFreeIds();
// _log.info("IDFactory: "+ freeIds.size() + " id's avaliable.");
java.sql.Connection con2 = null;
try
{
con2 = L2DatabaseFactory.getInstance().getConnection();
Statement s2 = con2.createStatement();
s2.executeUpdate("update characters set online=0");
_log.info("Updated characters online status.");
}
catch (SQLException e)
{
}
finally
{
try { con2.close(); } catch (Exception e) {}
}
}
private IdFactory(int i) {}
/**
* @param con
* @return
* @throws SQLException
*/
private int[] extractUsedObjectIDTable(java.sql.Connection con) throws SQLException
{
// create a temporary table
Statement s = con.createStatement();
s.executeUpdate("drop table if exists tmp_obj_id");
s.executeUpdate("create table tmp_obj_id (object_id int NOT NULL PRIMARY KEY)");
s.executeUpdate("insert into tmp_obj_id (object_id) select obj_id from characters");
s.executeUpdate("insert into tmp_obj_id (object_id) select clan_id from clan_data");
s.executeUpdate("update items i left join tmp_obj_id t on (i.object_id = t.object_id) set i.object_id = i.object_id + 200000000 where i.object_id IS NOT NULL AND t.object_id IS NOT NULL;");
s.executeUpdate("insert into tmp_obj_id (object_id) select object_id from items");
ResultSet result = s.executeQuery("select count(object_id) from tmp_obj_id ORDER BY object_id");
result.next();
int[] tmp_obj_ids = new int[result.getInt(1)];
// System.out.println("tmp table size: " + tmp_obj_ids.length);
result.close();
result = s.executeQuery("select object_id from tmp_obj_id ORDER BY object_id");
int idx = 0;
while (result.next())
{
tmp_obj_ids[idx++] = result.getInt(1);
}
result.close();
s.close();
return tmp_obj_ids;
}
public static void main(String[] args)
{
System.out.println("Commencing Database Reindexing.");
new IdFactory(1).reindex();
System.out.println("Finished Reindexing Database.");
}
public void reindex()
{
newFreeID = FIRST_OID;
java.sql.Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
// create a temporary table
int[] objectIds = extractUsedObjectIDTable(con);
ArrayList<Integer> objectIDList = new ArrayList<Integer>();
for (Integer oId: objectIds)
{
objectIDList.add(oId);
}
reindexCharacterIds(con, objectIDList);
reindexPetItemIds(con, objectIDList);
}
catch (Exception e1)
{
_log.severe("ID Factory could not be initialized correctly (2):" + e1);
e1.printStackTrace();
}
finally
{
try { con.close(); } catch (Exception e) {}
}
}
/**
* @param con
* @param objectIDList
*/
private static void reindexPetItemIds(Connection con, ArrayList<Integer> objectIDList) throws SQLException
{
System.out.println("Reindexing Pet Items.");
Statement s = con.createStatement();
ResultSet result = s.executeQuery("select count(item_obj_id) from pets");
result.next();
int[] characterIds = new int[result.getInt(1)];
result.close();
result = s.executeQuery("select item_obj_id from pets ORDER BY item_obj_id");
int idx = 0;
while (result.next())
{
characterIds[idx++] = result.getInt(1);
}
result.close();
int[] chars = {1,13};
for (Integer oldOID : characterIds)
{
//System.out.println("Reindexing Character ID: "+oldOID+".");
for (Integer updateId : chars)
{
String update = id_updates[updateId];
newFreeID = getNextUnusedID(objectIDList, newFreeID);
PreparedStatement ps = con.prepareStatement(update);
ps.setInt(1, oldOID);
ps.setInt(2, newFreeID);
ps.execute();
ps.close();
objectIDList.remove(oldOID);
}
System.out.println("Reindexed Pet Item from Old ID: "+oldOID+"\tto New ID: "+newFreeID+".");
}
System.out.println("Finished Reindexing Pet Items.");
}
/**
* @param newFreeID
* @param con
* @param objectIds
* @throws SQLException
*/
private static void reindexCharacterIds(java.sql.Connection con, ArrayList<Integer> objectIDList) throws SQLException
{
System.out.println("Reindexing Characters.");
Statement s = con.createStatement();
ResultSet result = s.executeQuery("select count(obj_id) from characters ORDER BY obj_id");
result.next();
int[] characterIds = new int[result.getInt(1)];
result.close();
result = s.executeQuery("select obj_id from characters ORDER BY obj_id");
int idx = 0;
while (result.next())
{
characterIds[idx++] = result.getInt(1);
}
result.close();
int[] chars = {0,2,3,4,6,7,8,12};
for (Integer oldOID : characterIds)
{
//System.out.println("Reindexing Character ID: "+oldOID+".");
for (Integer updateId : chars)
{
String update = id_updates[updateId];
newFreeID = getNextUnusedID(objectIDList, newFreeID);
PreparedStatement ps = con.prepareStatement(update);
ps.setInt(1, oldOID);
ps.setInt(2, newFreeID);
ps.execute();
ps.close();
objectIDList.remove(oldOID);
}
System.out.println("Reindexed Character from Old ID: "+oldOID+"\tto New ID: "+newFreeID+".");
}
System.out.println("Finished Reindexing Characters.");
}
private static int getNextUnusedID(ArrayList<Integer> objectIDList, int startIndex)
{
int id = startIndex+1;
while (id <= LAST_OID)
{
if (!objectIDList.contains(id))
{
return id;
}
id++;
}
return -1;
}
public boolean isInitialized() {
return initialized;
}
private int insertUntil(int[] tmp_obj_ids, int idx, int N,
java.sql.Connection con) throws SQLException
{
int id = tmp_obj_ids[idx];
if (id == _tempOID)
{
_tempOID++;
return N;
}
/*if (id == _curOID)
{
_curOID++;
return N;
}*/
// check these IDs not present in DB
for (String check : id_checks)
{
PreparedStatement ps = con.prepareStatement(check);
ps.setInt(1, _tempOID);
//ps.setInt(1, _curOID);
ps.setInt(2, id);
ResultSet rs = ps.executeQuery();
while (rs.next())
{
int badId = rs.getInt(1);
_log.severe("Bad ID " + badId + " in DB found by: " + check);
throw new RuntimeException();
}
rs.close();
ps.close();
}
//int hole = id - _curOID;
int hole = id - _tempOID;
if (hole > N - idx) hole = N - idx;
for (int i = 1; i <= hole; i++)
{
//long time1 = System.currentTimeMillis();
id = tmp_obj_ids[N - i];
//System.out.println("Compacting DB object ID=" + id + " into " + (_curOID));
/* for (String update : id_updates)
{
PreparedStatement ps = con.prepareStatement(update);
ps.setInt(1, _tempOID);
//ps.setInt(1, _curOID);
ps.setInt(2, id);
ps.execute();
ps.close();
}*/
System.out.println("Free ID added " + (_tempOID));
_freeOIDStack.push(_tempOID);
_tempOID++;
//_curOID++;
// System.out.println("T2: " + (System.currentTimeMillis() - time1));
}
//if (hole < N - idx) _curOID++;
if (hole < N - idx) _tempOID++;
// return N - hole;
return N - hole;
}
public static IdFactory getInstance()
{
return _instance;
}
public synchronized int getNextId()
{
/*if (Config.COMPACTION)
{
if (_freeSize == 0)
return _curOID++;
else
return _freeOIDs[--_freeSize];
}
else
{*/
int id;
if (!_freeOIDStack.empty())
id = _freeOIDStack.pop();
else
{
id = _curOID;
_curOID = _curOID+1;
}
System.out.println("Next id = " + id);
return id;
/* int newID = nextFreeId.get();
int nextFree = freeIds.nextClearBit(newID);
if (nextFree < 0)
nextFree = freeIds.nextClearBit(0);
if (nextFree < 0)
throw new NullPointerException("Ran out of valid Id's.");
nextFreeId.set(nextFree);
return newID + FIRST_OID;*/
// }
}
/**
* return a used Object ID back to the pool
* @param object ID
*/
public synchronized void releaseId(int id)
{
/* if (Config.COMPACTION)
{
if (_freeSize >= _freeOIDs.length)
{
int[] tmp = new int[_freeSize + STACK_SIZE_INCREMENT];
System.arraycopy(_freeOIDs, 0, tmp, 0, _freeSize);
_freeOIDs = tmp;
}
_freeOIDs[_freeSize++] = id;
}
else if (id >= FIRST_OID)
{
freeIds.clear(id-FIRST_OID);
freeIdCount.incrementAndGet();
}*/
_freeOIDStack.push(id);
System.out.println("Released id: " + id);
}
public int size()
{
if (!Config.COMPACTION)
{
return freeIdCount.get();
}
return _freeSize + LAST_OID - FIRST_OID;
}
private BitSet freeIds = null;
public void initialize()
{
try
{
freeIds = new BitSet(LAST_OID - FIRST_OID);
freeIdCount = new AtomicInteger(freeIds.size());
nextFreeId = new AtomicInteger(0);
freeIds.set(0);
//for (int objectID = FIRST_OID; objectID <= LAST_OID; objectID++)
//{
// freeIds.s(objectID);
//}
initialized = true;
}
catch (Exception e)
{
initialized = false;
e.printStackTrace();
}
}
/**
* @param id
*/
public synchronized void setObjectIDAsUsed(int id)
{
if (id >= FIRST_OID && !Config.COMPACTION)
{
freeIds.set(id-FIRST_OID);
freeIdCount.decrementAndGet();
}
}
}