mirror of https://github.com/perkeep/perkeep.git
135 lines
3.7 KiB
Go
135 lines
3.7 KiB
Go
/*
|
|
Copyright 2014 The Camlistore Authors
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
/*
|
|
Package mongo registers the "mongo" blobserver storage type, storing
|
|
blobs using MongoDB.
|
|
|
|
Sample (low-level) config:
|
|
"/bs/": {
|
|
"handler": "storage-mongo",
|
|
"handlerArgs": {
|
|
"host": "172.17.0.2",
|
|
"database": "camlitest"
|
|
}
|
|
},
|
|
|
|
Possible parameters:
|
|
host (optional, defaults to localhost)
|
|
database (required)
|
|
collection (optional, defaults to blobs)
|
|
user (optional)
|
|
password (optional)
|
|
*/
|
|
package mongo
|
|
|
|
import (
|
|
"camlistore.org/pkg/blobserver"
|
|
"camlistore.org/pkg/jsonconfig"
|
|
"camlistore.org/third_party/labix.org/v2/mgo"
|
|
)
|
|
|
|
type mongoStorage struct {
|
|
c *mgo.Collection
|
|
}
|
|
|
|
// blobDoc is the document that gets inserted in the MongoDB database
|
|
// Its fields are exported because they need to be for the mgo driver to pick them up
|
|
type blobDoc struct {
|
|
// Key contains the string representation of a blob reference (e.g. sha1-200d278aa6dd347f494407385ceab316440d5fba).
|
|
Key string
|
|
// Size contains the total size of a blob.
|
|
Size uint32
|
|
// Blob contains the raw blob data of the blob the above Key refers to.
|
|
Blob []byte
|
|
}
|
|
|
|
func init() {
|
|
blobserver.RegisterStorageConstructor("mongo", blobserver.StorageConstructor(newFromConfig))
|
|
}
|
|
|
|
func newFromConfig(_ blobserver.Loader, config jsonconfig.Obj) (blobserver.Storage, error) {
|
|
cfg, err := configFromJSON(config)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return newMongoStorage(cfg)
|
|
}
|
|
|
|
var uniqueKeyIndex = mgo.Index{
|
|
Key: []string{"key"},
|
|
Unique: true,
|
|
DropDups: false,
|
|
Background: false,
|
|
Sparse: false,
|
|
}
|
|
|
|
func newMongoStorage(cfg config) (blobserver.Storage, error) {
|
|
session, err := getConnection(cfg.url())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
c := session.DB(cfg.database).C(cfg.collection)
|
|
err = c.EnsureIndex(uniqueKeyIndex)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return blobserver.Storage(&mongoStorage{c: c}), nil
|
|
|
|
}
|
|
|
|
// Config holds the parameters used to connect to MongoDB.
|
|
type config struct {
|
|
server string // Required. Defaults to "localhost" in ConfigFromJSON.
|
|
database string // Required.
|
|
collection string // Required. Defaults to "blobs" in ConfigFromJSON.
|
|
user string // Optional, unless the server was configured with auth on.
|
|
password string // Optional, unless the server was configured with auth on.
|
|
}
|
|
|
|
func (cfg *config) url() string {
|
|
if cfg.user == "" || cfg.password == "" {
|
|
return cfg.server
|
|
}
|
|
return cfg.user + ":" + cfg.password + "@" + cfg.server + "/" + cfg.database
|
|
}
|
|
|
|
// ConfigFromJSON populates Config from cfg, and validates
|
|
// cfg. It returns an error if cfg fails to validate.
|
|
func configFromJSON(cfg jsonconfig.Obj) (config, error) {
|
|
conf := config{
|
|
server: cfg.OptionalString("host", "localhost"),
|
|
database: cfg.RequiredString("database"),
|
|
collection: cfg.OptionalString("collection", "blobs"),
|
|
user: cfg.OptionalString("user", ""),
|
|
password: cfg.OptionalString("password", ""),
|
|
}
|
|
if err := cfg.Validate(); err != nil {
|
|
return config{}, err
|
|
}
|
|
return conf, nil
|
|
}
|
|
|
|
func getConnection(url string) (*mgo.Session, error) {
|
|
session, err := mgo.Dial(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
session.SetMode(mgo.Monotonic, true)
|
|
session.SetSafe(&mgo.Safe{}) // so we get an ErrNotFound error when deleting an absent key
|
|
return session, nil
|
|
}
|