// Copyright 2014 by Sascha L. Teichmann // Use of this source code is governed by the MIT license // that can be found in the LICENSE file. package main import ( "flag" "fmt" "log" "net" "os" "os/signal" "runtime" "time" "bitbucket.org/s_l_teichmann/mtredisalize/common" ) const ( Version = "0.3" GCDuration = "24h" ) func main() { var ( port int host string driver string cacheSize int version bool gcDuration string ) flag.IntVar(&port, "port", 6379, "port to bind") flag.StringVar(&driver, "driver", "leveldb", "type of database (leveldb, sqlite)") flag.StringVar(&host, "host", "", "host to bind") flag.IntVar(&cacheSize, "cache", 32, "cache size in MB") flag.BoolVar(&version, "version", false, "Print version and exit.") flag.StringVar(&gcDuration, "gc-duration", GCDuration, "Duration between forced GCs.") flag.Parse() if version { fmt.Printf("Version: %s\n", Version) os.Exit(0) } args := flag.Args() if len(args) < 1 { log.Fatal("Missing path to world") } var ( err error backend Backend gcDur time.Duration ) if gcDur, err = time.ParseDuration(gcDuration); err != nil { log.Fatal(err) } if driver == "sqlite" { if backend, err = NewSqliteBackend( args[0], common.EncodeStringToBytes, common.DecodeStringFromBytes); err != nil { log.Fatal(err) } } else { if backend, err = NewLeveDBBackend(args[0], cacheSize); err != nil { log.Fatal(err) } } defer backend.Shutdown() var listener net.Listener listener, err = net.Listen("tcp", fmt.Sprintf("%s:%d", host, port)) if err != nil { log.Fatal(err) } defer listener.Close() log.Printf("Server started at %s", listener.Addr()) connChan := make(chan net.Conn) defer close(connChan) sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt, os.Kill) go func() { for { conn, err := listener.Accept() if err != nil { log.Fatal(err) } log.Printf("Client accepted from: %s", conn.RemoteAddr()) connChan <- conn } }() log.Printf("Doing garbage collection every: %s", gcDur) gcChan := time.Tick(gcDur) for { select { case conn := <-connChan: var session Session if session, err = backend.NewSession(); err != nil { log.Printf("Cannot create session: %s", err) conn.Close() } else { go NewConnection(conn, session).Run() } case <-sigChan: log.Println("Shutting down") return case <-gcChan: log.Println("Starting garbage collection.") runtime.GC() log.Println("Garbage collection done.") } } }