Esempio n. 1
0
func (self *SchemaInfo) Reload() {
	conn, err := self.ConnFactory()
	if err != nil {
		relog.Error("Could not get connection for reload: %v", err)
		return
	}
	defer conn.Close()

	query_for_schema_reload := fmt.Sprintf("show table status where unix_timestamp(create_time) > %v", self.LastReload.Unix())
	self.LastReload = time.Now()
	tables, err := conn.ExecuteFetch([]byte(query_for_schema_reload), 10000)
	if err != nil {
		relog.Error("Could not get table list for reload: %v", err)
		return
	}
	if len(tables.Rows) == 0 {
		return
	}
	for _, row := range tables.Rows {
		tableName := row[0].(string)
		relog.Info("Reloading: %s", tableName)
		tableInfo := self.get(tableName)
		if tableInfo != nil {
			self.Put(tableInfo)
			self.AlterTable(tableName, 0)
		} else {
			self.CreateTable(tableName, 0)
		}
	}
}
Esempio n. 2
0
func (service *UmgmtService) gracefulShutdown() {
	for e := service.shutdownCallbacks.Front(); e != nil; e = e.Next() {
		if callback, ok := e.Value.(ShutdownCallback); ok {
			callbackErr := callback()
			if callbackErr != nil {
				relog.Error("failed running shutdown callback:%v err:%v", callback, callbackErr)
			}
		} else {
			relog.Error("bad callback %T %v", callback, callback)
		}
	}
	service.done <- true
}
Esempio n. 3
0
func (client *Client) GracefulShutdown() error {
	request := new(Request)
	reply := new(Reply)
	err := client.Call("UmgmtService.GracefulShutdown", request, reply)
	if err != nil {
		relog.Error("rpc err: %v", err)
		return err
	}
	if reply.ErrorCode != 0 {
		relog.Error("GracefulShutdown err: %v %v", reply.ErrorCode, reply.Message)
		return errors.New(reply.Message)
	}
	return nil
}
Esempio n. 4
0
func (client *Client) CloseListeners() error {
	request := new(Request)
	reply := new(Reply)
	err := client.Call("UmgmtService.CloseListeners", request, reply)
	if err != nil {
		relog.Error("rpc err: %v", err)
		return err
	}
	if reply.ErrorCode != 0 {
		relog.Error("CloseListeners err: %v %v", reply.ErrorCode, reply.Message)
		return errors.New(reply.Message)
	}
	return nil
}
Esempio n. 5
0
func (self *httpHandler) ServeHTTP(c http.ResponseWriter, req *http.Request) {
	conn := &httpConnectionBroker{c, req.Body}
	codec := self.cFactory(conn)
	if err := rpc.ServeRequest(codec); err != nil {
		relog.Error("rpcwrap: %v", err)
	}
}
Esempio n. 6
0
func (server *UmgmtServer) Serve() error {
	relog.Info("started umgmt server: %v", server.listener.Addr())
	for !server.quit {
		conn, err := server.listener.Accept()
		if err != nil {
			if checkError(err, syscall.EINVAL) {
				if server.quit {
					return nil
				}
				return err
			}
			// syscall.EMFILE, syscall.ENFILE could happen here if you run out of file descriptors
			relog.Error("accept error %v", err)
			continue
		}

		server.Lock()
		server.connMap[conn] = true
		server.Unlock()

		rpc.ServeConn(conn)

		server.Lock()
		delete(server.connMap, conn)
		server.Unlock()
	}
	return nil
}
Esempio n. 7
0
func serve() {
	AddShutdownCallback(ShutdownCallback(func() error { relog.Error("testserver GracefulShutdown callback"); return nil }))
	err := ListenAndServe("/tmp/test-sock")
	if err != nil {
		relog.Fatal("listen err:%v", err)
	}
	relog.Info("test server finished")
}
Esempio n. 8
0
func (self *rpcHandler) ServeHTTP(c http.ResponseWriter, req *http.Request) {
	conn, _, err := c.(http.Hijacker).Hijack()
	if err != nil {
		relog.Error("rpc hijacking %s: %v", req.RemoteAddr, err)
		return
	}
	io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
	rpc.ServeCodec(self.cFactory(NewBufferedConnection(conn)))
}
Esempio n. 9
0
func (c *conn) serve() {
	defer func() {
		err := recover()
		if err == nil {
			return
		}

		relog.Error("panic serving %v: %v\n", c.remoteAddr, err)

		if c.rwc != nil {
			c.rwc.Close()
		}
		c.close()
	}()

	for {

		c.rwc.SetReadDeadline(time.Now().Add(agent_read_timeout))
		c.rwc.SetWriteDeadline(time.Now().Add(agent_write_timeout))

		req, err := readRequest(c.rw.Reader)

		if err != nil {
			msg := "CLIENT_ERROR"
			if err == io.EOF {
				break
			} else if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
				break
			}
			fmt.Fprintf(c.rwc, "%s %s\r\n", msg, err)
			continue
		}

		err = c.handle_request(req)
		if err != nil {
			relog.Error("handle requesr error(%s)", err)
			break
		}

		c.rw.Flush()
	}

	c.close()
}
Esempio n. 10
0
func (self *ActivePool) kill(connid int64) {
	self.Remove(connid)
	killStats.Add("Queries", 1)
	relog.Info("killing query %d", connid)
	killConn := self.connPool.Get()
	defer killConn.Recycle()
	sql := []byte(fmt.Sprintf("kill %d", connid))
	if _, err := killConn.ExecuteFetch(sql, 10000); err != nil {
		relog.Error("Could not kill query %d: %v", connid, err)
	}
}
Esempio n. 11
0
func handleError(err *error) {
	if x := recover(); x != nil {
		terr := x.(*TabletError)
		*err = terr
		terr.RecordStats()
		if terr.ErrorType == RETRY { // Retry errors are too spammy
			return
		}
		relog.Error("%s", terr.Message)
	}
}
Esempio n. 12
0
// this is a callback to bind and startup an http server.
// usually it is called like:
//   umgmt.AddStartupCallback(func () { umgmt.StartHttpServer(addr) })
func StartHttpServer(addr string) {
	httpListener, httpErr := net.Listen("tcp", addr)

	go func() {
		if httpErr == nil {
			httpListener = newHttpListener(httpListener)
			AddListener(httpListener)
			httpErr = http.Serve(httpListener, nil)
			httpListener.Close()
		}
		if httpErr != nil {
			switch e := httpErr.(type) {
			case *net.OpError:
				switch e.Err {
				case syscall.EADDRINUSE:
					relog.Fatal("StartHttpServer failed: %v", e)
				}
			case error:
				// NOTE(msolomon) even though these are Errno objects, the constants
				// are typed as os.Error.
				switch e {
				// FIXME(msolomon) this needs to be migrated into the system library
				// because this needs to be properly handled in the accept loop.
				case syscall.EMFILE, syscall.ENFILE:
					relog.Error("non-fatal error serving HTTP: %s", e.Error())
				case syscall.EINVAL:
					// nothing - listener was probably closed
				default:
					relog.Error("http.ListenAndServe: " + httpErr.Error())
				}
			default:
				relog.Error("http.ListenAndServe: " + httpErr.Error())
			}
		}
	}()
}
Esempio n. 13
0
func (service *UmgmtService) closeListeners() (err error) {
	service.mutex.Lock()
	defer service.mutex.Unlock()
	for e := service.listeners.Front(); e != nil; e = e.Next() {
		// NOTE(msolomon) we don't need the whole Listener interface, just Closer
		//relog.Info("closeListeners %T %v", _listener, _listener)
		if listener, ok := e.Value.(io.Closer); ok {
			closeErr := listener.Close()
			if closeErr != nil {
				errMsg := fmt.Sprintf("failed to close listener:%v err:%v", listener, closeErr)
				// just return that at least one error happened, the log will reveal the rest
				err = errors.New(errMsg)
				relog.Error("%s", errMsg)
			}
			// FIXME(msolomon) add a meaningful message telling what listener was closed
		} else {
			relog.Error("bad listener %T %v", listener, listener)
		}
	}
	for _, f := range service.closeCallbacks {
		go f()
	}
	return
}
Esempio n. 14
0
func ListenAndServe(addr string) error {
	rpc.Register(&defaultService)
	DefaultServer = new(UmgmtServer)
	DefaultServer.connMap = make(map[net.Conn]bool)
	defer DefaultServer.Close()

	var umgmtClient *Client

	for i := 2; i > 0; i-- {
		l, e := net.Listen("unix", addr)
		if e != nil {
			if checkError(e, syscall.EADDRINUSE) {
				var clientErr error
				umgmtClient, clientErr = Dial(addr)
				if clientErr == nil {
					closeErr := umgmtClient.CloseListeners()
					if closeErr != nil {
						relog.Error("closeErr:%v", closeErr)
					}
					// wait for rpc to finish
					if rebindDelay > 0.0 {
						relog.Info("delaying rebind: %vs", rebindDelay)
						time.Sleep(rebindDelay)
					}
					continue
				} else if checkError(clientErr, syscall.ECONNREFUSED) {
					if unlinkErr := syscall.Unlink(addr); unlinkErr != nil {
						relog.Error("can't unlink %v err:%v", addr, unlinkErr)
					}
				} else {
					return e
				}
			} else {
				return e
			}
		} else {
			DefaultServer.listener = l
			break
		}
	}
	if DefaultServer.listener == nil {
		panic("unable to rebind umgmt socket")
	}
	// register the umgmt server itself for dropping - this seems like
	// the common case. i can't see when you *wouldn't* want to drop yourself
	defaultService.addListener(DefaultServer)
	defaultService.addShutdownCallback(func() error {
		return DefaultServer.handleGracefulShutdown()
	})

	// fire off the startup callbacks. if these bind ports, they should
	// call AddListener.
	for e := defaultService.startupCallbacks.Front(); e != nil; e = e.Next() {
		if startupCallback, ok := e.Value.(StartupCallback); ok {
			startupCallback()
		} else {
			relog.Error("bad callback %T %v", e.Value, e.Value)
		}
	}

	if umgmtClient != nil {
		go func() {
			time.Sleep(lameDuckPeriod)
			umgmtClient.GracefulShutdown()
			umgmtClient.Close()
		}()
	}
	return DefaultServer.Serve()
}
Esempio n. 15
0
func main() {
	memProfileRate := flag.Int("mem-profile-rate", 512*1024, "profile every n bytes allocated")
	maxOpenFds := flag.Uint64("max-open-fds", 32768, "max open file descriptors")
	configFile := flag.String("config", "", "config file name")
	dbConfigFile := flag.String("dbconfig", "", "db config file name")
	lameDuckPeriod := flag.Float64("lame-duck-period", DefaultLameDuckPeriod,
		"how long to give in-flight transactions to finish")
	rebindDelay := flag.Float64("rebind-delay", DefaultRebindDelay,
		"artificial delay before rebinding a hijacked listener")
	logfileName := flag.String("logfile", "/dev/stderr", "base log file name")
	logFrequency := flag.Int64("logfile.frequency", 0, "rotation frequency in seconds")
	logMaxSize := flag.Int64("logfile.maxsize", 0, "max file size in bytes")
	logMaxFiles := flag.Int64("logfile.maxfiles", 0, "max number of log files")
	queryLog := flag.String("querylog", "", "for testing: log all queries to this file")
	flag.Parse()

	exportBinaryVersion()

	runtime.MemProfileRate = *memProfileRate

	f, err := logfile.Open(*logfileName, *logFrequency, *logMaxSize, *logMaxFiles)
	if err != nil {
		panic(fmt.Sprintf("unable to open logfile %s", *logfileName))
	}
	logger := relog.New(f, "vtocc ",
		log.Ldate|log.Lmicroseconds|log.Lshortfile, relog.DEBUG)
	relog.SetLogger(logger)
	if *queryLog != "" {
		if f, err = os.OpenFile(*queryLog, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644); err == nil {
			ts.QueryLogger = relog.New(f, "", log.Ldate|log.Lmicroseconds, relog.DEBUG)
		}
	}
	unmarshalFile(*configFile, &config)
	unmarshalFile(*dbConfigFile, &dbconfig)
	// work-around for jsonism
	if v, ok := dbconfig["port"].(float64); ok {
		dbconfig["port"] = int(v)
	}

	fdLimit := &syscall.Rlimit{*maxOpenFds, *maxOpenFds}
	if err = syscall.Setrlimit(RLIMIT_NOFILE, fdLimit); err != nil {
		relog.Fatal("can't Setrlimit %#v: err %v", *fdLimit, err)
	} else {
		relog.Info("set max-open-fds = %v", *maxOpenFds)
	}

	snitch.RegisterCommand("reload_schema", "Rescan the schema for new tables", ReloadHandler)
	snitch.Register()

	qm := &OccManager{config, dbconfig}
	rpc.Register(qm)

	ts.StartQueryService(
		config.PoolSize,
		config.TransactionCap,
		config.TransactionTimeout,
		config.MaxResultSize,
		config.QueryCacheSize,
		config.SchemaReloadTime,
		config.QueryTimeout,
		config.IdleTimeout,
	)
	ts.AllowQueries(ts.GenericConnectionCreator(dbconfig), nil)

	rpc.HandleHTTP()
	jsonrpc.ServeHTTP()
	jsonrpc.ServeRPC()
	bsonrpc.ServeHTTP()
	bsonrpc.ServeRPC()

	relog.Info("started vtocc %v", config.Port)

	// we delegate out startup to the micromanagement server so these actions
	// will occur after we have obtained our socket.

	usefulLameDuckPeriod := float64(config.QueryTimeout + 1)
	if usefulLameDuckPeriod > *lameDuckPeriod {
		*lameDuckPeriod = usefulLameDuckPeriod
		relog.Info("readjusted -lame-duck-period to %f", *lameDuckPeriod)
	}
	umgmt.SetLameDuckPeriod(float32(*lameDuckPeriod))
	umgmt.SetRebindDelay(float32(*rebindDelay))
	umgmt.AddStartupCallback(func() {
		umgmt.StartHttpServer(fmt.Sprintf(":%v", config.Port))
	})
	umgmt.AddStartupCallback(func() {
		sighandler.SetSignalHandler(syscall.SIGTERM,
			umgmt.SigTermHandler)
	})
	umgmt.AddCloseCallback(func() {
		ts.DisallowQueries()
	})
	umgmt.AddShutdownCallback(func() error {
		HandleGracefulShutdown()
		return nil
	})

	umgmtSocket := fmt.Sprintf(config.UmgmtSocket, config.Port)
	if umgmtErr := umgmt.ListenAndServe(umgmtSocket); umgmtErr != nil {
		relog.Error("umgmt.ListenAndServe err: %v", umgmtErr)
	}
	relog.Info("done")
}
Esempio n. 16
0
func (self *SqlQuery) Execute(query *Query, reply *QueryResult) (err error) {
	defer func() {
		if x := recover(); x != nil {
			terr := x.(*TabletError)
			err = terr
			terr.RecordStats()
			if terr.ErrorType == RETRY || terr.SqlError == DUPLICATE_KEY { // suppress these errors in logs
				return
			}
			relog.Error("%s: %v", terr.Message, query)
		}
	}()
	// allow shutdown state if we're in a transaction
	allowShutdown := (query.TransactionId != 0)
	self.checkState(query.SessionId, allowShutdown)

	self.mu.RLock()
	defer self.mu.RUnlock()

	if query.BindVariables == nil { // will help us avoid repeated nil checks
		query.BindVariables = make(map[string]interface{})
	}
	// cheap hack: strip trailing comment into a special bind var
	stripTrailing(query)
	basePlan, tableInfo := self.schemaInfo.GetPlan(query.Sql, len(query.BindVariables) != 0)
	defer self.schemaInfo.Put(tableInfo)
	plan := &CompiledPlan{basePlan, tableInfo, query.BindVariables, query.TransactionId, query.ConnectionId}

	// Need upfront connection for DMLs and transactions
	if query.TransactionId != 0 {
		conn := self.activeTxPool.Get(query.TransactionId)
		defer conn.Recycle()
		var invalidator CacheInvalidator
		if tableInfo != nil && tableInfo.CacheType != 0 {
			invalidator = conn.DirtyKeys(plan.TableName)
		}
		switch plan.PlanId {
		case sqlparser.PLAN_PASS_DML:
			defer queryStats.Record("PASS_DML", time.Now())
			*reply = *self.directFetch(conn, plan.FullQuery, plan.BindVars, nil, nil)
		case sqlparser.PLAN_INSERT_PK:
			defer queryStats.Record("PLAN_INSERT_PK", time.Now())
			*reply = *self.execInsertPK(conn, plan, invalidator)
		case sqlparser.PLAN_INSERT_SUBQUERY:
			defer queryStats.Record("PLAN_INSERT_SUBQUERY", time.Now())
			*reply = *self.execInsertSubquery(conn, plan, invalidator)
		case sqlparser.PLAN_DML_PK:
			defer queryStats.Record("DML_PK", time.Now())
			*reply = *self.execDMLPK(conn, plan, invalidator)
		case sqlparser.PLAN_DML_SUBQUERY:
			defer queryStats.Record("DML_SUBQUERY", time.Now())
			*reply = *self.execDMLSubquery(conn, plan, invalidator)
		default: // select or set in a transaction, just count as select
			defer queryStats.Record("PASS_SELECT", time.Now())
			*reply = *self.directFetch(conn, plan.FullQuery, plan.BindVars, nil, nil)
		}
	} else {
		switch plan.PlanId {
		case sqlparser.PLAN_PASS_SELECT:
			if plan.Reason == sqlparser.REASON_FOR_UPDATE {
				panic(NewTabletError(FAIL, "Disallowed outside transaction: %s", query.Sql))
			}
			defer queryStats.Record("PASS_SELECT", time.Now())
			*reply = *self.qFetch(plan, plan.FullQuery, nil)
		case sqlparser.PLAN_SELECT_PK:
			defer queryStats.Record("SELECT_PK", time.Now())
			*reply = *self.execPK(plan)
		case sqlparser.PLAN_SELECT_SUBQUERY:
			defer queryStats.Record("SELECT_SUBQUERY", time.Now())
			*reply = *self.execSubquery(plan)
		case sqlparser.PLAN_SELECT_CACHE_RESULT:
			defer queryStats.Record("SELECT_CACHE_RESULT", time.Now())
			*reply = *self.execCacheResult(plan)
		case sqlparser.PLAN_SET:
			defer queryStats.Record("SET", time.Now())
			*reply = *self.execSet(plan)
		default:
			panic(NewTabletError(FAIL, "DMLs not allowed outside of transactions"))
		}
	}
	if plan.PlanId.IsSelect() {
		resultStats.Add(int64(reply.RowsAffected))
	}
	return nil
}
Esempio n. 17
0
func logError() {
	if x := recover(); x != nil {
		relog.Error("%s", x.(*TabletError).Message)
	}
}