phex.download.DownloadDataWriter.java Source code

Java tutorial

Introduction

Here is the source code for phex.download.DownloadDataWriter.java

Source

/*
 *  PHEX - The pure-java Gnutella-servent.
 *  Copyright (C) 2001 - 2008 Phex Development Group
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 *  --- SVN Information ---
 *  $Id$
 */
package phex.download;

import java.util.List;
import java.util.ListIterator;

import org.apache.commons.lang.time.DateUtils;

import phex.common.ThreadTracking;
import phex.download.swarming.SWDownloadFile;
import phex.download.swarming.SwarmingManager;
import phex.prefs.core.DownloadPrefs;

/**
 * Extra thread that is responsible to write buffered download data to
 * disk regulary.
 */
public class DownloadDataWriter implements Runnable {
    private Thread thread;
    private boolean isShutingDown;
    private long lastCompleteWrite;
    private boolean isWriteCycleRequested;
    private SwarmingManager swarmingMgr;

    public DownloadDataWriter(SwarmingManager downloadService) {
        swarmingMgr = downloadService;
    }

    public void start() {
        isShutingDown = false;
        thread = new Thread(ThreadTracking.rootThreadGroup, this, "DownloadDataWriter");
        thread.setDaemon(true);
        thread.start();
    }

    /**
     * This call performs a shutdown of the download data writer thread.
     * The call blocks until the DownloadDataWriter thread died.
     */
    public void shutdown() {
        isShutingDown = true;
        // trigger thread cycle
        triggerWriteCycle();
        try {
            thread.join();
        } catch (InterruptedException exp) {
            //NLogger.error( DownloadDataWriter.class, exp, exp );
            Thread.currentThread().interrupt();
        }

        // perform a last write operation to ensure all data is on disk
        writeDownloadData();
    }

    public void run() {
        while (!isShutingDown) {
            try {
                do {
                    writeDownloadData();
                } while (isWriteCycleRequested);
                // loop around write cycles as long as data is filling...
                // this is necessary for very fast downloads..
                waitForNotify();
            } catch (Throwable th) {
                //NLogger.error( DownloadDataWriter.class, th, th );
            }
        }
    }

    private synchronized void waitForNotify() {
        //NLogger.debug(DownloadDataWriter.class, "Waiting..." );
        try {
            wait(5000);
        } catch (InterruptedException exp) {
            //NLogger.error( DownloadDataWriter.class, exp, exp );
        }
        //NLogger.debug(DownloadDataWriter.class, "Woke..." );
    }

    public synchronized void triggerWriteCycle() {
        //NLogger.debug(DownloadDataWriter.class, "Triggering write cycle." );
        isWriteCycleRequested = true;
        notifyAll();
    }

    private void writeDownloadData() {
        if (!swarmingMgr.isDownloadActive() && !isWriteCycleRequested) {
            return;
        }

        long bufferedDataWritten = 0;
        long totalBufferedSize = 0;
        boolean performCompleteWrite = false;
        if (isShutingDown || isWriteCycleRequested
                || lastCompleteWrite + DateUtils.MILLIS_PER_MINUTE < System.currentTimeMillis()) {
            //NLogger.debug(DownloadDataWriter.class, "Time for complete write cycle." );
            isWriteCycleRequested = false;
            performCompleteWrite = true;
        }

        // write limit is 90% of configured max.
        int maxPerDownloadBuffer = DownloadPrefs.MaxWriteBufferPerDownload.get().intValue();
        maxPerDownloadBuffer = (int) (maxPerDownloadBuffer * 0.9);

        List<SWDownloadFile> downloadList = swarmingMgr.getDownloadFileListCopy();
        ListIterator<SWDownloadFile> iterator = downloadList.listIterator();
        while (iterator.hasNext()) {
            SWDownloadFile downloadFile = iterator.next();
            MemoryFile memoryFile = downloadFile.getMemoryFile();
            long bufferedSize = memoryFile.getBufferedDataLength();
            totalBufferedSize += bufferedSize;

            if (performCompleteWrite || memoryFile.isBufferWritingRequested()
                    || bufferedSize >= maxPerDownloadBuffer) {
                //NLogger.debug(DownloadDataWriter.class,
                //   "Trigger buffer write for " + downloadFile + 
                //   ", amount: " + bufferedSize );
                memoryFile.writeBuffersToDisk();
                bufferedDataWritten += bufferedSize;
                // remove from buffer since not needed anymore in possible
                // following complete write cycle
                iterator.remove();
            }
        }

        //NLogger.debug(DownloadDataWriter.class,
        //   "Total buffered data was: " + totalBufferedSize );

        // write limit is 90% of configured max.
        int maxTotalBuffer = DownloadPrefs.MaxTotalDownloadWriteBuffer.get().intValue();
        maxTotalBuffer = (int) (maxTotalBuffer * 0.9);

        // if we have not already written everything but have a high total buffer
        // size, we write down the complete remaining download buffers to disk.
        if (!performCompleteWrite && totalBufferedSize >= maxTotalBuffer) {
            performCompleteWrite = true;
            iterator = downloadList.listIterator();
            while (iterator.hasNext()) {
                SWDownloadFile downloadFile = iterator.next();
                MemoryFile memoryFile = downloadFile.getMemoryFile();
                long bufferedSize = memoryFile.getBufferedDataLength();
                //NLogger.debug(DownloadDataWriter.class,
                //                    "Trigger buffer write for " + downloadFile + 
                //                    ", amount: " + bufferedSize );
                memoryFile.writeBuffersToDisk();
                bufferedDataWritten += bufferedSize;
            }
        }
        if (performCompleteWrite) {
            lastCompleteWrite = System.currentTimeMillis();
        }
        if (bufferedDataWritten > 0) {
            swarmingMgr.notifyDownloadListChange();
        }
    }
}