2015-06-08 17 views
5

Bolt erhält eine Dateisperre für die Datendatei, sodass mehrere Prozesse nicht dieselbe Datenbank gleichzeitig öffnen können. Wenn Sie eine bereits geöffnete Bolt-Datenbank öffnen, bleibt sie hängen, bis der andere Prozess sie schließt.Boltdb-Schlüssel-Wert Datenspeicher rein in Go

Wie ist dies der Fall, gibt es ein Konzept für die Verbindungspooling wie verschiedene Clients verbinden und Zugriff auf die Datenbank zur gleichen Zeit.? Ist das in boltdb möglich? Es gibt verschiedene Verbindungen, die gleichzeitig in der Datenbank lesen und schreiben. Wie kann es implementiert werden?

+1

Als eine dateibasierte DB, ist es unwahrscheinlich, aufgrund der Art und Weise arbeiten Dateisperren zu ändern. Dies ist wahrscheinlich auch eine bessere Frage auf dem Bolt-Repository als StackOverflow: https://github.com/boltb/bolt – elithrar

Antwort

9

A Bolt-Datenbank wird in der Regel in ein größeres Programm eingebettet ist und nicht über das Netzwerk verwendet, wie Sie mit gemeinsam genutzten Datenbanken würde (man denke SQLite vs MySQL). Die Verwendung von Bolt ist ein bisschen wie eine persistente map[[]byte][]byte, wenn das möglich wäre. Je nachdem, was Sie tun, möchten Sie vielleicht etwas wie Redis verwenden.

Das heißt, wenn Sie Bolzen auf diese Weise verwenden müssen, ist es nicht sehr schwierig, mit einem einfachen Server zu wickeln. Hier ist ein Beispiel, das Schlüssel aus einer Bolt DB über HTTP schreibt/liest. Sie können Keep-Alive für Verbindungspooling verwenden.

-Code an: https://github.com/skyec/boltdb-server

package main 

import (
    "flag" 
    "fmt" 
    "io/ioutil" 
    "log" 
    "net/http" 
    "time" 

    "github.com/boltdb/bolt" 
    "github.com/gorilla/mux" 
) 

type server struct { 
    db *bolt.DB 
} 

func newServer(filename string) (s *server, err error) { 
    s = &server{} 
    s.db, err = bolt.Open(filename, 0600, &bolt.Options{Timeout: 1 * time.Second}) 
    return 
} 

func (s *server) Put(bucket, key, contentType string, val []byte) error { 
    return s.db.Update(func(tx *bolt.Tx) error { 
     b, err := tx.CreateBucketIfNotExists([]byte(bucket)) 
     if err != nil { 
      return err 
     } 
     if err = b.Put([]byte(key), val); err != nil { 
      return err 
     } 
     return b.Put([]byte(fmt.Sprintf("%s-ContentType", key)), []byte(contentType)) 
    }) 
} 

func (s *server) Get(bucket, key string) (ct string, data []byte, err error) { 
    s.db.View(func(tx *bolt.Tx) error { 
     b := tx.Bucket([]byte(bucket)) 
     r := b.Get([]byte(key)) 
     if r != nil { 
      data = make([]byte, len(r)) 
      copy(data, r) 
     } 

     r = b.Get([]byte(fmt.Sprintf("%s-ContentType", key))) 
     ct = string(r) 
     return nil 
    }) 
    return 
} 

func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { 
    vars := mux.Vars(r) 

    if vars["bucket"] == "" || vars["key"] == "" { 
     http.Error(w, "Missing bucket or key", http.StatusBadRequest) 
     return 
    } 

    switch r.Method { 
    case "POST", "PUT": 
     data, err := ioutil.ReadAll(r.Body) 
     if err != nil { 
      http.Error(w, err.Error(), http.StatusInternalServerError) 
      return 
     } 
     err = s.Put(vars["bucket"], vars["key"], r.Header.Get("Content-Type"), data) 
     w.WriteHeader(http.StatusOK) 
    case "GET": 
     ct, data, err := s.Get(vars["bucket"], vars["key"]) 
     if err != nil { 
      http.Error(w, err.Error(), http.StatusInternalServerError) 
      return 
     } 
     w.Header().Add("Content-Type", ct) 
     w.Write(data) 
    } 
} 

func main() { 
    var (
     addr string 
     dbfile string 
    ) 

    flag.StringVar(&addr, "l", ":9988", "Address to listen on") 
    flag.StringVar(&dbfile, "db", "/var/data/bolt.db", "Bolt DB file") 
    flag.Parse() 

    log.Println("Using Bolt DB file:", dbfile) 
    log.Println("Listening on:", addr) 

    server, err := newServer(dbfile) 
    if err != nil { 
     log.Fatalf("Error: %s", err) 
    } 

    router := mux.NewRouter() 
    router.Handle("/v1/buckets/{bucket}/keys/{key}", server) 
    http.Handle("/", router) 

    log.Fatal(http.ListenAndServe(addr, nil)) 
} 
+0

Vielen Dank! Ich habe verstanden, wie es sich von anderen Datenbanken unterscheidet, die im Netzwerk geteilt werden. Es wird von einem Prozess verwaltet, der eine API über das Netzwerk verfügbar macht. –

+0

Klingt gut. Ein Vorteil des Einbettens einer Speicher-Engine besteht darin, dass Sie die Schnittstelle für Ihre spezifischen Anforderungen erstellen können. Verwenden Sie nur kleine Schlüssel und Werte, bei denen der Durchsatz zählt? Machen Sie es zu einer UDP-Schnittstelle. Oder vielleicht ist eine protobuf-Schnittstelle für Sie besser geeignet. Ich werde an diesem Code als Nebenprojekt basteln. Also werde ich wahrscheinlich jeden von ihnen versuchen. Viel Glück. – SkyeC

+0

Es gibt verschiedene eindeutige ID und alle bieten einen Betrag von Millisekunden und ich muss es speichern und ihre aktuellen Ausgaben (die Summe der Gebote bis zu dieser Zeit) so schnell wie möglich aktualisieren. Das Schema, das ich verwende, ist wie - ein Eimer für jede eindeutige ID und speichert die Zeit als Schlüssel und Wert als das Gebot. --ein gemeinsamer Eimer für alle einzigartig und aktualisieren ihre aktuellen Ausgaben in diesem wo Schlüssel = eindeutige ID und Wert = neueste aktuelle ausgeben. Wie in diesem Fall sollte ich welche Schnittstelle bevorzugen. Und wie kann ich die Rate der Aktualisierung des Wertes erhöhen, z. B. sollte ich db.Update() oder db.Batch() verwenden und wie? –

4

Es gibt kein Verbindungs-Pooling-Konzept in boltdb, da keine Verbindung besteht. Es ist keine Client/Server-Datenbank, sondern eine eingebettete Datenbank (wie sqlite oder Berkeley-DB).

Boltdb ist so konzipiert, dass mehrere goroutines des gleichen Prozesses auf die Datenbank zur gleichen Zeit (mit verschiedenen Transaktionen) zugreifen können. Das Modell ist ein einzelner Autor, mehrere Leser. Boltdb ist nicht dafür ausgelegt, Zugriffe von mehreren Prozessen zu unterstützen.

Wenn Sie ein Go-Programm benötigen Unterstützung eine eingebettete Datenbank zu verwenden, um Zugriff von mehreren Prozessen gleichzeitig, können Sie einen Blick auf die Wrapper über LMDB haben wollen, wie zum Beispiel:

+0

Okay! Vielen Dank. Kann jemand ein boltDB-Tag erstellen, um weitere Abfragen einfach verwalten zu können? –

+0

boltb tag wurde gerade hinzugefügt. –

+0

Vielen Dank für das Hinzufügen! –