2015-06-08 16 views
5

Bolt lấy khóa tệp trên tệp dữ liệu để nhiều quá trình không thể mở cùng một cơ sở dữ liệu cùng một lúc. Việc mở một cơ sở dữ liệu Bolt đã mở sẽ khiến nó bị treo cho đến khi quá trình khác đóng nó lại.Lưu trữ dữ liệu khóa-giá trị Boltdb hoàn toàn trong Go

Vì đây là trường hợp, có bất kỳ khái niệm tổng hợp kết nối nào giống như các máy khách khác nhau đang kết nối và truy cập cơ sở dữ liệu cùng một lúc không? Điều này có thể xảy ra trong boltdb không? Giống như có nhiều kết nối khác nhau đọc và ghi trong cơ sở dữ liệu cùng một lúc. Làm thế nào nó có thể được thực hiện?

+1

Là một tệp cơ sở dữ dựa trên, đó là khó có thể thay đổi do cách khóa tập tin làm việc. Đây cũng có thể là câu hỏi hay hơn về kho lưu trữ Bolt thay vì StackOverflow: https://github.com/boltdb/bolt – elithrar

Trả lời

9

Cơ sở dữ liệu Bolt thường được nhúng vào một chương trình lớn hơn và không được sử dụng trên mạng như bạn làm với cơ sở dữ liệu được chia sẻ (nghĩ SQLite vs MySQL). Sử dụng Bolt hơi giống một số liên tục map[[]byte][]byte nếu có thể. Tùy thuộc vào những gì bạn đang làm, bạn có thể muốn chỉ sử dụng một cái gì đó như Redis.

Điều đó nói rằng, nếu bạn cần sử dụng Bolt theo cách này, nó không phải là rất khó khăn để bọc với một máy chủ đơn giản. Đây là một ví dụ viết/đọc các khóa từ một Bolt DB qua HTTP. Bạn có thể sử dụng Keep-Alive để kết nối tổng hợp.

Mã tại địa chỉ: 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

Cảm ơn rất nhiều! Tôi hiểu sự khác biệt của nó với các cơ sở dữ liệu khác được chia sẻ trên network.will có nó thuộc sở hữu của một quá trình cho thấy một API trên mạng. –

+0

Âm thanh tốt. Một lợi ích của việc gói một công cụ lưu trữ như thế này là bạn có thể xây dựng giao diện để đáp ứng các nhu cầu cụ thể của bạn. Bạn chỉ sử dụng các khóa và giá trị nhỏ mà thông lượng quan trọng? Biến nó thành giao diện UDP. Hoặc có thể giao diện protobuf phù hợp hơn với bạn. Tôi sẽ tiếp tục tinkering với mã này như là một dự án phụ. Vì vậy, có lẽ sẽ cố gắng mỗi trong số này. May mắn nhất. – SkyeC

+0

Có nhiều id duy nhất và tất cả đang đặt giá thầu với số tiền bằng một phần nghìn giây và tôi phải lưu trữ và cập nhật chi tiêu hiện tại của họ (tổng số tiền giá thầu cho đến thời điểm đó) càng sớm càng tốt. Giản đồ tôi đang sử dụng giống như - một nhóm cho mỗi id duy nhất và lưu trữ thời gian dưới dạng khóa và giá trị làm giá thầu. - một nhóm phổ biến cho tất cả duy nhất và cập nhật chi tiêu hiện tại của chúng trong đó trong đó khóa = id duy nhất và giá trị = chi tiêu hiện tại mới nhất. Như trong trường hợp này, tôi nên sử dụng giao diện nào. Và làm cách nào tôi có thể tăng tốc độ cập nhật giá trị, tức là tôi có thể sử dụng db.Update() hoặc db.Batch() và làm cách nào? –

4

Không có khái niệm tổng hợp kết nối trong boltdb, vì không có kết nối. Nó không phải là một cơ sở dữ liệu máy khách/máy chủ, nó là một cơ sở dữ liệu nhúng (như sqlite hoặc Berkeley-DB).

Boltdb được thiết kế sao cho nhiều goroutines của cùng một quy trình có thể truy cập cơ sở dữ liệu cùng một lúc (sử dụng các giao dịch khác nhau). Mô hình là một người viết, nhiều độc giả. Boltdb không được thiết kế để hỗ trợ truy cập từ nhiều quy trình.

Nếu bạn cần một chương trình Go để sử dụng một cơ sở dữ liệu nhúng hỗ trợ truy cập từ nhiều quy trình cùng một lúc, bạn có thể muốn có một cái nhìn tại wrappers qua LMDB, chẳng hạn như:

+0

OK! Cảm ơn. Ai cũng có thể tạo một thẻ boltDB để dễ quản lý các truy vấn thêm. –

+0

Thẻ boltb vừa được thêm vào. –

+0

Cảm ơn bạn đã thêm! –

Các vấn đề liên quan