Home Download Docs Code Community
     1	/*
     2	Copyright 2014 The Perkeep Authors
     3	
     4	Licensed under the Apache License, Version 2.0 (the "License");
     5	you may not use this file except in compliance with the License.
     6	You may obtain a copy of the License at
     7	
     8	     http://www.apache.org/licenses/LICENSE-2.0
     9	
    10	Unless required by applicable law or agreed to in writing, software
    11	distributed under the License is distributed on an "AS IS" BASIS,
    12	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13	See the License for the specific language governing permissions and
    14	limitations under the License.
    15	*/
    16	
    17	/*
    18	Package mongo registers the "mongo" blobserver storage type, storing
    19	blobs using MongoDB.
    20	
    21	Sample (low-level) config:
    22	
    23		"/bs/": {
    24		    "handler": "storage-mongo",
    25		    "handlerArgs": {
    26		       "host": "172.17.0.2",
    27		       "database": "camlitest"
    28		     }
    29		},
    30	
    31	Possible parameters:
    32	host (optional, defaults to localhost)
    33	database (required)
    34	collection (optional, defaults to blobs)
    35	user (optional)
    36	password (optional)
    37	*/
    38	package mongo // import "perkeep.org/pkg/blobserver/mongo"
    39	
    40	import (
    41		"go4.org/jsonconfig"
    42		"go4.org/legal"
    43		"gopkg.in/mgo.v2"
    44		"perkeep.org/pkg/blobserver"
    45	)
    46	
    47	type mongoStorage struct {
    48		c *mgo.Collection
    49	}
    50	
    51	// blobDoc is the document that gets inserted in the MongoDB database
    52	// Its fields are exported because they need to be for the mgo driver to pick them up
    53	type blobDoc struct {
    54		// Key contains the string representation of a blob reference (e.g. sha1-200d278aa6dd347f494407385ceab316440d5fba).
    55		Key string
    56		// Size contains the total size of a blob.
    57		Size uint32
    58		// Blob contains the raw blob data of the blob the above Key refers to.
    59		Blob []byte
    60	}
    61	
    62	func init() {
    63		blobserver.RegisterStorageConstructor("mongo", blobserver.StorageConstructor(newFromConfig))
    64		legal.RegisterLicense(`
    65	For Mongo Driver
    66	mgo - MongoDB driver for Go
    67	Copyright (c) 2010-2013 - Gustavo Niemeyer <gustavo@niemeyer.net>
    68	All rights reserved.
    69	`)
    70	}
    71	
    72	func newFromConfig(_ blobserver.Loader, config jsonconfig.Obj) (blobserver.Storage, error) {
    73		cfg, err := configFromJSON(config)
    74		if err != nil {
    75			return nil, err
    76		}
    77		return newMongoStorage(cfg)
    78	}
    79	
    80	var uniqueKeyIndex = mgo.Index{
    81		Key:        []string{"key"},
    82		Unique:     true,
    83		DropDups:   false,
    84		Background: false,
    85		Sparse:     false,
    86	}
    87	
    88	func newMongoStorage(cfg config) (blobserver.Storage, error) {
    89		session, err := getConnection(cfg.url())
    90		if err != nil {
    91			return nil, err
    92		}
    93		c := session.DB(cfg.database).C(cfg.collection)
    94		err = c.EnsureIndex(uniqueKeyIndex)
    95		if err != nil {
    96			return nil, err
    97		}
    98		return blobserver.Storage(&mongoStorage{c: c}), nil
    99	
   100	}
   101	
   102	// Config holds the parameters used to connect to MongoDB.
   103	type config struct {
   104		server     string // Required. Defaults to "localhost" in ConfigFromJSON.
   105		database   string // Required.
   106		collection string // Required. Defaults to "blobs" in ConfigFromJSON.
   107		user       string // Optional, unless the server was configured with auth on.
   108		password   string // Optional, unless the server was configured with auth on.
   109	}
   110	
   111	func (cfg *config) url() string {
   112		if cfg.user == "" || cfg.password == "" {
   113			return cfg.server
   114		}
   115		return cfg.user + ":" + cfg.password + "@" + cfg.server + "/" + cfg.database
   116	}
   117	
   118	// ConfigFromJSON populates Config from cfg, and validates
   119	// cfg. It returns an error if cfg fails to validate.
   120	func configFromJSON(cfg jsonconfig.Obj) (config, error) {
   121		conf := config{
   122			server:     cfg.OptionalString("host", "localhost"),
   123			database:   cfg.RequiredString("database"),
   124			collection: cfg.OptionalString("collection", "blobs"),
   125			user:       cfg.OptionalString("user", ""),
   126			password:   cfg.OptionalString("password", ""),
   127		}
   128		if err := cfg.Validate(); err != nil {
   129			return config{}, err
   130		}
   131		return conf, nil
   132	}
   133	
   134	func getConnection(url string) (*mgo.Session, error) {
   135		session, err := mgo.Dial(url)
   136		if err != nil {
   137			return nil, err
   138		}
   139		session.SetMode(mgo.Monotonic, true)
   140		session.SetSafe(&mgo.Safe{}) // so we get an ErrNotFound error when deleting an absent key
   141		return session, nil
   142	}
Website layout inspired by memcached.
Content by the authors.