ed.net.lb.LB.java Source code

Java tutorial

Introduction

Here is the source code for ed.net.lb.LB.java

Source

// LB.java

/**
*      Copyright (C) 2008 10gen Inc.
*  
*    Licensed under the Apache License, Version 2.0 (the "License");
*    you may not use this file except in compliance with the License.
*    You may obtain a copy of the License at
*  
*       http://www.apache.org/licenses/LICENSE-2.0
*  
*    Unless required by applicable law or agreed to in writing, software
*    distributed under the License is distributed on an "AS IS" BASIS,
*    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*    See the License for the specific language governing permissions and
*    limitations under the License.
*/

package ed.net.lb;

import java.io.*;
import java.net.*;
import java.nio.*;
import java.util.*;
import java.util.concurrent.*;
import java.text.*;

import org.apache.commons.cli.*;

import ed.io.*;
import ed.js.*;
import ed.log.*;
import ed.util.*;
import ed.net.*;
import ed.net.nioclient.*;
import ed.cloud.*;
import ed.net.httpserver.*;
import static ed.net.lb.Mapping.*;

public class LB extends NIOClient {

    static final String LBIDENT = DNSUtil.getLocalHost().getHostName() + " : v0";

    enum State {
        WAITING, IN_HEADER, READY_TO_STREAM, STREAMING, ERROR, DONE
    };

    public LB(int port, MappingFactory mappingFactory, int verbose) throws IOException {
        super("LB", 2000, verbose);

        _port = port;
        _handler = new LBHandler();

        _logger = Logger.getLogger("LB");
        _logger.setLevel(Level.forDebugId(verbose));

        _server = new HttpServer(port);
        _server.addGlobalHandler(_handler);

        _router = new Router(mappingFactory);
        _loadMonitor = new LoadMonitor(_router);

        _addMonitors();

        _httpLog = new AsyncAppender();
        _httpLog.addAppender(new DailyFileAppender(new File("logs/httplog/"), "lb", new HttpLogEventFormatter()));

        setDaemon(true);
    }

    public void start() {
        _server.start();
        super.start();
    }

    public void run() {
        _logger.debug("Started");
        try {
            super.run();
        } catch (Throwable t) {
            try {
                System.err.println("LB run got error");
                t.printStackTrace();
            } catch (Throwable t2) {
            }
            System.exit(-1);
        }
    }

    protected void shutdown() {
        _logger.error("SHUTDOWN starting");
        _server.stopServer();
        super.shutdown();
        Thread t = new Thread() {
            public void run() {
                try {
                    Thread.sleep(1000 * 60);
                } catch (Exception e) {
                }
                System.exit(0);
            }
        };
        t.start();
    }

    protected void serverError(InetSocketAddress addr, ServerErrorType type, Exception why) {
        // TODO: uh oh
        _logger.debug(1, "serverError", addr + ":" + type);
    }

    class LBHandler implements HttpHandler {
        public boolean handles(HttpRequest request, Info info) {
            info.admin = false;
            info.fork = false;
            info.doneAfterHandles = false;
            return true;
        }

        public boolean handle(HttpRequest request, HttpResponse response) {

            if (request.getHeader("X-fromlb") != null) {
                _handleError(request, response, 500,
                        "load balancer loop?  (lb 34)\n" + request.getFullURL() + "\n" + "physical address:"
                                + request.getPhysicalRemoteAddr() + "\n" + "remote address:"
                                + request.getRemoteIP());
                return true;
            }

            if (_router.reject(request)) {
                _handleError(request, response, 403, "request rejected");
                return true;
            }

            if (add(new LBCall(LB.this, request, response)))
                return false;

            _handleError(request, response, 500, "new request queue full  (lb 1)");
            return true;
        }

        private void _handleError(HttpRequest request, HttpResponse response, int code, String msg) {
            response.setResponseCode(code);
            JxpWriter out = response.getJxpWriter();
            out.print(msg);
            out.print("\n");
            try {
                response.done();
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }

        public double priority() {
            return Double.MAX_VALUE;
        }
    }

    void log(LBCall rr) {
        _httpLog.append(new HttpEvent(rr));
    }

    protected void setNumSelectors(int total) {
        super.setNumSelectors(total);
        _server.setStat("lb-selectors", total);
    }

    void _addMonitors() {
        HttpServer.addGlobalHandler(new WebViews.LBOverview(this));
        HttpServer.addGlobalHandler(new WebViews.LBLast(this));

        HttpServer.addGlobalHandler(new WebViews.LoadMonitorWebView(this._loadMonitor));
        HttpServer.addGlobalHandler(new WebViews.SiteLoadMonitorWebView(this._loadMonitor));

        HttpServer.addGlobalHandler(new WebViews.RouterPools(this._router));
        HttpServer.addGlobalHandler(new WebViews.RouterServers(this._router));
        HttpServer.addGlobalHandler(new WebViews.MappingView(this._router));

        HttpServer.addGlobalHandler(new HttpHandler() {
            public boolean handles(HttpRequest request, Info info) {
                if (!"/~kill".equals(request.getURI()))
                    return false;

                if (!"127.0.0.1".equals(request.getPhysicalRemoteAddr()))
                    return false;

                info.fork = false;
                info.admin = true;

                return true;
            }

            public boolean handle(HttpRequest request, HttpResponse response) {
                JxpWriter out = response.getJxpWriter();
                if (isShutDown()) {
                    out.print("alredy shutdown");
                    return true;
                }
                LB.this.shutdown();
                out.print("done");
                return true;
            }

            public double priority() {
                return Double.MIN_VALUE;
            }
        });
    }

    class HttpLogEventFormatter implements EventFormatter {

        public synchronized String format(Event old) {
            HttpEvent e = (HttpEvent) old;
            LBCall rr = e._rr;

            _buf.append("[").append(e.getDate().format(_dateFormat)).append("] "); // 1
            _buf.append(rr._request.getRemoteIP()); // 2 
            _buf.append(" retry:").append(rr._numFails); // 3
            _buf.append(" went:").append(rr.lastWent()); // 4
            _buf.append(" ").append(rr._response.getResponseCode()); // 5
            _buf.append(" ").append(rr._request.getMethod()); // 6
            _buf.append(" \"").append(rr._request.getFullURL()).append("\""); // 7
            _buf.append(" ").append(rr._response.handleTime()); // 8 
            _buf.append(" \"").append(rr._request.getHeader("User-Agent")).append("\""); // 9
            _buf.append(" \"").append(rr._request.getHeader("Referer")).append("\""); // 10 
            _buf.append(" \"").append(rr._request.getHeader("Cookie")).append("\""); // 11
            _buf.append("\n");

            String s = _buf.toString();
            if (_buf.length() > _bufSize)
                _buf = new StringBuilder(_bufSize);
            else
                _buf.setLength(0);
            return s;
        }

        final int _bufSize = 1024;
        StringBuilder _buf = new StringBuilder(_bufSize);
    }

    class HttpEvent extends Event {
        HttpEvent(LBCall rr) {
            super(null, rr._request.getStart(), null, null, null, null);
            _rr = rr;
        }

        final LBCall _rr;
    }

    final int _port;
    final LBHandler _handler;
    final HttpServer _server;
    final Router _router;
    final LoadMonitor _loadMonitor;

    final Logger _logger;
    final AsyncAppender _httpLog;

    final CircularList<LBCall> _lastCalls = new CircularList<LBCall>(1000, true);

    static final SimpleDateFormat _dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.SSS z");

    public static void main(String args[]) throws Exception {

        int verbose = 0;

        for (int i = 0; i < args.length; i++) {
            if (args[i].matches("\\-v+")) {
                verbose = args[i].length() - 1;
                args[i] = "";
            }
        }

        Options o = new Options();
        o.addOption("p", "port", true, "Port to Listen On");
        o.addOption("v", "verbose", false, "Verbose");
        o.addOption("mapfile", "m", true, "file from which to load mappings");

        CommandLine cl = (new BasicParser()).parse(o, args);

        final int port = Integer.parseInt(cl.getOptionValue("p", "8080"));

        MappingFactory mf = null;
        if (cl.hasOption("m"))
            mf = new TextMapping.Factory(cl.getOptionValue("m", null));
        else
            mf = new GridMapping.Factory();

        System.out.println("10gen load balancer");
        System.out.println("\t port \t " + port);
        System.out.println("\t verbose \t " + verbose);

        int retriesLeft = 2;

        HttpMonitor.setApplicationType("Load Balancer");

        LB lb = null;

        while (retriesLeft-- > 0) {

            try {
                lb = new LB(port, mf, verbose);
                break;
            } catch (BindException be) {
                be.printStackTrace();
                System.out.println("can't bind to port.  going to try to kill old one");
                HttpDownload.downloadToJS(new URL("http://127.0.0.1:" + port + "/~kill"));
                Thread.sleep(100);
            }
        }

        if (lb == null) {
            System.err.println("couldn't ever bind");
            System.exit(-1);
            return;
        }

        lb.start();
        lb.join();
        System.exit(0);
    }
}