Merge pull request #119 from benbjohnson/rmdb

Add endpoint for database deletion.
This commit is contained in:
tgruben 2016-10-04 13:03:03 -05:00 committed by GitHub
commit 2e81850c03
4 changed files with 130 additions and 0 deletions

View file

@ -106,6 +106,13 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
}
case "/db":
switch r.Method {
case "DELETE":
h.handleDeleteDB(w, r)
default:
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
}
case "/db/attr/diff":
switch r.Method {
case "POST":
@ -264,6 +271,33 @@ type sliceMaxResponse struct {
SliceMax uint64 `json:"SliceMax"`
}
// handleDeleteDB handles DELETE /db request.
func (h *Handler) handleDeleteDB(w http.ResponseWriter, r *http.Request) {
// Decode request.
var req deleteDBRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Delete database from the index.
if err := h.Index.DeleteDB(req.DB); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Encode response.
if err := json.NewEncoder(w).Encode(deleteDBResponse{}); err != nil {
h.logger().Printf("response encoding error: %s", err)
}
}
type deleteDBRequest struct {
DB string `json:"db"`
}
type deleteDBResponse struct{}
// handlePostDBAttrDiff handles POST /db/attr/diff requests.
func (h *Handler) handlePostDBAttrDiff(w http.ResponseWriter, r *http.Request) {
// Decode request.

View file

@ -416,6 +416,42 @@ func TestHandler_Query_ErrParse(t *testing.T) {
}
}
// Ensure the handler can delete a database.
func TestHandler_DB_Delete(t *testing.T) {
idx := MustOpenIndex()
defer idx.Close()
s := NewServer()
s.Handler.Index = idx.Index
defer s.Close()
// Create database.
if _, err := idx.CreateDBIfNotExists("d"); err != nil {
t.Fatal(err)
}
// Send request to delete database.
resp, err := http.DefaultClient.Do(MustNewHTTPRequest("DELETE", s.URL+"/db", strings.NewReader(`{"db":"d"}`)))
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
// Verify body response.
if resp.StatusCode != http.StatusOK {
t.Fatalf("unexpected status: %d", resp.StatusCode)
} else if buf, err := ioutil.ReadAll(resp.Body); err != nil {
t.Fatal(err)
} else if string(buf) != "{}\n" {
t.Fatalf("unexpected response body: %s", buf)
}
// Verify database is gone.
if idx.DB("d") != nil {
t.Fatal("expected nil database")
}
}
// Ensure the handler can return data in differing blocks for a database.
func TestHandler_DB_AttrStore_Diff(t *testing.T) {
idx := MustOpenIndex()

View file

@ -183,6 +183,33 @@ func (i *Index) createDBIfNotExists(name string) (*DB, error) {
return db, nil
}
// DeleteDB removes a database from the index.
func (i *Index) DeleteDB(name string) error {
i.mu.Lock()
defer i.mu.Unlock()
// Ignore if database doesn't exist.
db := i.db(name)
if db == nil {
return nil
}
// Close database.
if err := db.Close(); err != nil {
return err
}
// Delete database directory.
if err := os.RemoveAll(i.DBPath(name)); err != nil {
return err
}
// Remove reference.
delete(i.dbs, name)
return nil
}
// Frame returns the frame for a database and name.
func (i *Index) Frame(db, name string) *Frame {
d := i.DB(db)

View file

@ -11,6 +11,39 @@ import (
"github.com/umbel/pilosa/pql"
)
// Ensure index can delete a database and its underlying files.
func TestIndex_DeleteDB(t *testing.T) {
idx := MustOpenIndex()
defer idx.Close()
// Write bits to separate databases.
f0 := idx.MustCreateFragmentIfNotExists("d0", "f", 0)
if _, err := f0.SetBit(100, 200, nil, 0); err != nil {
t.Fatal(err)
}
f1 := idx.MustCreateFragmentIfNotExists("d1", "f", 0)
if _, err := f1.SetBit(100, 200, nil, 0); err != nil {
t.Fatal(err)
}
// Ensure d0 exists.
if _, err := os.Stat(idx.DBPath("d0")); err != nil {
t.Fatal(err)
}
// Delete d0.
if err := idx.DeleteDB("d0"); err != nil {
t.Fatal(err)
}
// Ensure d0 files are removed & d1 still exists.
if _, err := os.Stat(idx.DBPath("d0")); !os.IsNotExist(err) {
t.Fatal("expected d0 file deletion")
} else if _, err := os.Stat(idx.DBPath("d1")); err != nil {
t.Fatal("expected d1 files to still exist", err)
}
}
// Ensure index can sync with a remote index.
func TestIndexSyncer_SyncIndex(t *testing.T) {
cluster := NewCluster(2)