Beispiel #1
0
func (s *Server) execute(tx bool, stmts []string) ([]FailedSqlStmt, error) {
	var failures = make([]FailedSqlStmt, 0)

	if tx {
		log.Trace("Transaction requested")
		s.metrics.executeTxReceived.Inc(1)

		_, err := s.raftServer.Do(command.NewTransactionExecuteCommandSet(stmts))
		if err != nil {
			log.Tracef("Transaction failed: %s", err.Error())
			s.metrics.executeFail.Inc(1)
			failures = append(failures, FailedSqlStmt{stmts[0], err.Error()})
		} else {
			s.metrics.executeSuccess.Inc(1)
		}
	} else {
		log.Trace("No transaction requested")
		for i := range stmts {
			_, err := s.raftServer.Do(command.NewExecuteCommand(stmts[i]))
			if err != nil {
				log.Tracef("Execute statement %s failed: %s", stmts[i], err.Error())
				s.metrics.executeFail.Inc(1)
				failures = append(failures, FailedSqlStmt{stmts[i], err.Error()})
			} else {
				s.metrics.executeSuccess.Inc(1)
			}

		}
	}

	return failures, nil
}
Beispiel #2
0
// Recovery restores the state of the database using the given data.
func (d *DbStateMachine) Recovery(b []byte) error {
	log.Tracef("Restoring database state to path: %s", d.dbpath)
	err := ioutil.WriteFile(d.dbpath, b, os.ModePerm)
	if err != nil {
		log.Errorf("Failed to recover state: %s", err.Error())
		return err
	}
	log.Tracef("Database restored successfully to %s", d.dbpath)
	return nil
}
Beispiel #3
0
// Save captures the state of the database. The caller must ensure that
// no transaction is taking place during this call.
//
// http://sqlite.org/howtocorrupt.html states it is safe to do this
// as long as no transaction is in progress.
func (d *DbStateMachine) Save() ([]byte, error) {
	log.Tracef("Capturing database state from path: %s", d.dbpath)
	b, err := ioutil.ReadFile(d.dbpath)
	if err != nil {
		log.Errorf("Failed to save state: %s", err.Error())
		return nil, err
	}
	log.Tracef("Database state successfully saved to %s", d.dbpath)
	return b, nil
}
Beispiel #4
0
func (s *Server) readHandler(w http.ResponseWriter, req *http.Request) {
	log.Tracef("readHandler for URL: %s", req.URL)
	s.metrics.queryReceived.Inc(1)

	var failures = make([]FailedSqlStmt, 0)

	// Get the query statement
	stmt, err := stmtParam(req)
	if err != nil {
		log.Tracef("Bad HTTP request: %s", err.Error())
		w.WriteHeader(http.StatusBadRequest)
		s.metrics.queryFail.Inc(1)
		return
	}

	startTime := time.Now()
	r, err := s.db.Query(stmt)
	if err != nil {
		log.Tracef("Bad SQL statement: %s", err.Error())
		s.metrics.queryFail.Inc(1)
		failures = append(failures, FailedSqlStmt{stmt, err.Error()})
	} else {
		s.metrics.querySuccess.Inc(1)
	}
	duration := time.Since(startTime)

	rr := QueryResponse{Failures: failures, Rows: r}
	if e, _ := isExplain(req); e {
		rr.Time = duration.String()
	}

	pretty, _ := isPretty(req)
	var b []byte
	if pretty {
		b, err = json.MarshalIndent(rr, "", "    ")
	} else {
		b, err = json.Marshal(rr)
	}
	if err != nil {
		log.Tracef("Failed to marshal JSON data: %s", err.Error())
		http.Error(w, err.Error(), http.StatusBadRequest) // Internal error actually
	} else {
		_, err = w.Write([]byte(b))
		if err != nil {
			log.Errorf("Error writting JSON data: %s", err.Error())
		}
	}
}
Beispiel #5
0
// NewDbStateMachine returns a StateMachine for capturing and restoring
// the state of an sqlite database.
func NewDbStateMachine(path string) *DbStateMachine {
	d := &DbStateMachine{
		dbpath: path,
	}
	log.Tracef("New DB state machine created with path: %s", path)
	return d
}
Beispiel #6
0
// Open an existing database, creating it if it does not exist.
func Open(dbPath string) *DB {
	log.Tracef("Opening SQLite database path at %s", dbPath)
	dbc, err := sql.Open("sqlite3", dbPath)
	if err != nil {
		log.Error(err.Error())
		return nil
	}
	return &DB{
		dbConn: dbc,
	}
}
Beispiel #7
0
// Apply executes a set of sqlite statements, within a transaction. All statements
// will take effect, or none.
func (c *TransactionExecuteCommandSet) Apply(server raft.Server) (interface{}, error) {
	log.Tracef("Applying TransactionExecuteCommandSet of size %d", len(c.Stmts))

	commitSuccess := false
	db := server.Context().(*db.DB)
	defer func() {
		if !commitSuccess {
			err := db.RollbackTransaction()
			if err != nil {
				log.Errorf("Failed to rollback transaction: %s", err.Error())
			}
		}
	}()

	err := db.StartTransaction()
	if err != nil {
		log.Errorf("Failed to start transaction: %s", err.Error())
		return nil, err
	}

	for i := range c.Stmts {
		err = db.Execute(c.Stmts[i])
		if err != nil {
			log.Errorf("Failed to execute statement within transaction: %s", err.Error())
			return nil, err
		}
	}

	if err = db.CommitTransaction(); err != nil {
		log.Errorf("Failed to commit transaction: %s", err.Error())
		return nil, err
	}

	commitSuccess = true
	return nil, nil
}
Beispiel #8
0
// New creates a new database. Deletes any existing database.
func New(dbPath string) *DB {
	log.Tracef("Removing any existing SQLite database at %s", dbPath)
	_ = os.Remove(dbPath)
	return Open(dbPath)
}
Beispiel #9
0
func (s *Server) writeHandler(w http.ResponseWriter, req *http.Request) {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	if s.raftServer.State() != "leader" {
		s.leaderRedirect(w, req)
		return
	}

	log.Tracef("writeHandler for URL: %s", req.URL)
	s.metrics.executeReceived.Inc(1)

	currentIndex := s.raftServer.CommitIndex()
	count := currentIndex - s.snapConf.lastIndex
	if uint64(count) > s.snapConf.snapshotAfter {
		log.Info("Committed log entries snapshot threshold reached, starting snapshot")
		err := s.raftServer.TakeSnapshot()
		s.logSnapshot(err, currentIndex, count)
		s.snapConf.lastIndex = currentIndex
		s.metrics.snapshotCreated.Inc(1)
	}

	// Read the value from the POST body.
	b, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Tracef("Bad HTTP request: %s", err.Error())
		s.metrics.executeFail.Inc(1)
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	stmts := strings.Split(string(b), ";")
	if stmts[len(stmts)-1] == "" {
		stmts = stmts[:len(stmts)-1]
	}

	log.Tracef("Execute statement contains %d commands", len(stmts))
	if len(stmts) == 0 {
		log.Trace("No database execute commands supplied")
		s.metrics.executeFail.Inc(1)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	transaction, _ := isTransaction(req)
	startTime := time.Now()
	failures, err := s.execute(transaction, stmts)
	if err != nil {
		log.Errorf("Database mutation failed: %s", err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	duration := time.Since(startTime)

	wr := StmtResponse{Failures: failures}
	if e, _ := isExplain(req); e {
		wr.Time = duration.String()
	}

	pretty, _ := isPretty(req)
	if pretty {
		b, err = json.MarshalIndent(wr, "", "    ")
	} else {
		b, err = json.Marshal(wr)
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	} else {
		_, err = w.Write([]byte(b))
		if err != nil {
			log.Errorf("Error writting JSON data: %s", err.Error())
		}
	}
}
Beispiel #10
0
// Apply executes an sqlite statement.
func (c *ExecuteCommand) Apply(server raft.Server) (interface{}, error) {
	log.Tracef("Applying ExecuteCommand: '%s'", c.Stmt)
	db := server.Context().(*db.DB)
	return nil, db.Execute(c.Stmt)
}