/* * Copyright 2011 Tyler Blair. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are those of the * authors and contributors and should not be interpreted as representing official policies, * either expressed or implied, of anybody else. */ package com.griefcraft.util; import com.griefcraft.lwc.LWC; import com.griefcraft.model.Protection; import com.griefcraft.sql.Database; import java.util.Iterator; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; public class DatabaseThread implements Runnable { /** * The LWC object */ private final LWC lwc; /** * The protections waiting to be updated in the database */ private final Queue<Protection> updateQueue = new ConcurrentLinkedQueue<Protection>(); /** * The thread we are running in */ private final Thread thread = new Thread(this); /** * If the database thread is active and running */ private boolean running = false; /** * The last time the queue was flushed to the database */ private long lastFlush = -1L; /** * The time the next keepalive packet will be sent at */ private long nextKeepalivePacket = 0; /** * Interval between pinging the database */ private int pingInterval = 0; public DatabaseThread(LWC lwc) { this.lwc = lwc; this.running = true; this.lastFlush = System.currentTimeMillis(); this.thread.start(); pingInterval = lwc.getConfiguration().getInt("database.ping_interval", 300); } /** * Adds a protection to the update queue so that it is flushed to the database asap * * @param protection */ public void addProtection(Protection protection) { updateQueue.offer(protection); } /** * Removes a protection from the update queue * * @param protection */ public void removeProtection(Protection protection) { updateQueue.remove(protection); } /** * Gets the current amount of protections queued to be updated * * @return the amount of protections queued to be updated */ public int size() { return updateQueue.size(); } /** * Stop the database thread */ public void stop() { // stop running and interrupt the thread running = false; if (!thread.isInterrupted()) { thread.interrupt(); } // Flush the rest of the entries flushDatabase(); } /** * Recommend a flush as soon as possible. This does not guarantee the database will be flushed immediately. */ public void flush() { lastFlush = System.currentTimeMillis() - 9999999L; } /** * Flush the protections to the database */ private void flushDatabase() { if (!updateQueue.isEmpty()) { Database database = lwc.getPhysicalDatabase(); database.setAutoCommit(false); database.setUseStatementCache(false); // Begin iterating through the queue Iterator<Protection> iter = updateQueue.iterator(); while (iter.hasNext()) { Protection protection = iter.next(); iter.remove(); protection.saveNow(); } // Commit the changes to the database database.setUseStatementCache(true); database.setAutoCommit(true); } // update the time we last flushed at lastFlush = System.currentTimeMillis(); if (System.currentTimeMillis() > nextKeepalivePacket && lwc.getPhysicalDatabase().isConnected()) { nextKeepalivePacket = System.currentTimeMillis() + (pingInterval * 1000); lwc.getPhysicalDatabase().pingDatabase(); } } public void run() { while (running) { // how many seconds between each flush int interval = lwc.getConfiguration().getInt("core.flushInterval", 5); if (interval > 120) { interval = 120; } long currentTime = System.currentTimeMillis(); long intervalMilliseconds = interval * 1000L; // compare the current time to the last flush if (currentTime - lastFlush > intervalMilliseconds) { flushDatabase(); } try { Thread.sleep(1000L); } catch (InterruptedException e) { running = false; } } } }