All pastes #20973 Raw Edit

Untitled

public text v1 · immutable
#20973 ·published 2005-08-24 12:22 UTC
rendered paste body
public 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();
        }
    }
}