001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.issue.lbcore258;
015
016import java.io.FileOutputStream;
017import java.io.IOException;
018import java.nio.channels.FileChannel;
019import java.nio.channels.FileLock;
020
021/**
022 *  FileLockSimulator is a small application intended to simulate FileAppender in prudent mode.
023 * In this mode, the application obtains an exclusive lock on the file, writes to the file and
024 * then releases the lock.
025 *
026 * <pre>  Usage:
027 *   java  FileLockSimulator instanceName pathToLogFile delay
028 * where
029 * "instanceName" is the name given to the current instance of the application
030 * "pathToLogFile" is the path to the log file
031 * "delay" is the number of milliseconds of sleep observed every 128 writes
032 * </pre>
033 *
034 * <b>This small application requires only the JDK to compile and to execute.</b>
035 *
036 * <p>FileLockSimulator should be launched as many times and from as many hosts as there will be
037 * JVMs writing to a log file in prudent mode. Performance should be quite good if
038 * "pathToLogFile" is on a local file system. On networked file systems such as NFS, performance
039 * depends on the speed of the network and NFS implementation. It has been observed that file
040 * locking over NFS is biased so that the current owner of the lock is favored over other processes.
041 * Thus, while one process hogs the lock for the log file, other processes starve waiting for the
042 * lock to the point of appearing deadlocked.
043 *
044 */
045public class FileLockSimulator {
046
047    static String LINE_SEPARATOR = System.getProperty("line.separator");
048    static final int DOT_FREQ = 128;
049    static final int DOT_WITH_NEW_LINE_FREQ = DOT_FREQ * 80;
050
051    static String instanceName;
052    static int delay;
053    static FileOutputStream fos;
054    static FileChannel fileChannel;
055
056    public static void main(String[] args) throws IOException, InterruptedException {
057
058        String instanceName = args[0];
059        System.out.println("Instance named as [" + instanceName + "]");
060
061        String fileStr = args[1];
062        System.out.println("Output target specified as [" + fileStr + "]");
063
064        int delay = Integer.parseInt(args[2]);
065        System.out.println("Sleep delay specified as [" + delay + "] milliseconds");
066
067        fos = new FileOutputStream(fileStr, true);
068        fileChannel = fos.getChannel();
069
070        for (int i = 1;; i++) {
071            printDotAndSleep(i);
072            lockAndWrite(i);
073        }
074    }
075
076    static void lockAndWrite(int i) throws InterruptedException, IOException {
077        FileLock fileLock = null;
078        try {
079            fileLock = fileChannel.lock();
080            long position = fileChannel.position();
081            long size = fileChannel.size();
082            if (size != position) {
083                fileChannel.position(size);
084            }
085            String msg = "hello from" + instanceName + " " + i + LINE_SEPARATOR;
086            fos.write(msg.getBytes());
087        } finally {
088            if (fileLock != null) {
089                fileLock.release();
090            }
091        }
092    }
093
094    static void printDotAndSleep(int i) throws InterruptedException {
095        if (i % DOT_FREQ == 0) {
096            System.out.print(".");
097            Thread.sleep(delay);
098        }
099        if (i % DOT_WITH_NEW_LINE_FREQ == 0)
100            System.out.println("");
101    }
102}