Example #1
0
// GetIDRecord returns the ID record for a given idname. It also
// will error if the ID has exceeded its max permitted value.
func (mkv *MongoKV) GetIDRecord(idname string) (IDRecord, error) {
	var result IDRecord
	err := mkv.DBs["id"].FindOne(bson.M{"key": idname}, &result)
	if err != nil {
		return result, util.NewWebError(500, "STAT-102", fmt.Sprintf("Incremented ID '%s' but didn't find it!", idname)).Add("mongoerr", err.Error())
	}

	if result.Value >= result.Max {
		return result, util.NewWebError(500, "STAT-103",
			fmt.Sprintf("ID max %d exceeded for IDName %s. Unable to create new ID.", result.Max, idname))
	}
	return result, nil
}
Example #2
0
// GetIDFor is like GetNextID, except that it takes a "hash" value;
// if the hash exists, it always returns the same key value for it.
// if the hash doesn't exist, then it generates a new key and stores it
// under that hash.
func (mkv *MongoKV) GetIDFor(idname string, hash string) (string, error) {
	var result map[string]interface{}
	hashsel := bson.M{"hash": hash, "idname": idname}
	if err := mkv.DBs["id"].FindOne(hashsel, &result); err == nil {
		switch id := result["id"].(type) {
		case int:
			// if it's an int, we need to prefix it appropriately
			idrec, err := mkv.GetIDRecord(idname)
			if err != nil {
				return "", err
			}
			sid := fmt.Sprintf("%s%d", idrec.Prefix, id)
			return sid, nil
		case string:
			// if it's a string, we have what we need
			return id, nil
		}
	}

	// if we get here, the hash wasn't found
	id, err := mkv.GetNextID(idname)
	if err != nil {
		return "", err
	}

	// now we have id, store it under the hash
	newhash := bson.M{"hash": hash, "idname": idname, "id": id}
	err = mkv.DBs["id"].Insert(newhash)
	if err != nil {
		return id, util.NewWebError(500, "STAT-103",
			fmt.Sprintf("Got ID %d from '%s' for '%s' but couldn't store it!", id, idname, hash)).Add("mongoerr", err.Error())
	}

	return id, nil
}
Example #3
0
// GetNextID increments the ID value for the given idname
// and returns an appropriately-prefixed ID for that name.
func (mkv *MongoKV) GetNextID(idname string) (string, error) {
	selector := bson.M{"key": idname}
	update := bson.M{"$inc": bson.M{"value": 1}}
	err := mkv.DBs["id"].Update(selector, update)
	if err != nil {
		return "", util.NewWebError(404, "STAT-101", fmt.Sprintf("No id found with name '%s'", idname)).Add("mongoerr", err.Error())
	}

	idrec, err := mkv.GetIDRecord(idname)
	if err != nil {
		return "", err
	}
	id := fmt.Sprintf("%s%d", idrec.Prefix, idrec.Value)

	return id, nil
}
Example #4
0
func (ss *StaticServer) PostKey(rw http.ResponseWriter, req *http.Request) {
	key := bone.GetValue(req, "key")

	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		util.WriteWebError(rw, util.NewWebError(http.StatusBadRequest, "STAT-211", err.Error()))
	}
	b := string(body)
	value := getJSON(b)
	ss.setS3RootIfPresent(key, value)

	if err := ss.mkv.Upsert(key, value); err != nil {
		util.WriteError(rw, "STAT-212", err)
		return
	}
	util.WriteJSON(rw, value)
}
Example #5
0
func (mkv *MongoKV) Reconnect(m *mongoHelper.M) error {
	// we want to make sure that our writes get to disk
	m.Sess.SetSafe(&mgo.Safe{})
	m.Sess.SetMode(mgo.Strong, false)

	index1 := mgo.Index{
		Key:        []string{"key"},
		Unique:     true,
		DropDups:   true,
		Background: true, // See notes.
		Sparse:     true,
	}
	err := m.Coll.EnsureIndex(index1)
	if err != nil {
		return util.NewWebError(http.StatusInternalServerError,
			"STAT-101", fmt.Sprintf("Error creating index1")).Add("original", err.Error())
	}

	return nil
}
// Connect will connect to the MongoDB server(s) specified in the URL.
// It also supports connections where ssl is enabled.
func (m *M) Connect() error {
	var (
		err      error
		useSSL   bool
		sess     *mgo.Session
		dialInfo *mgo.DialInfo
	)

	// Do this to allow mgo.ParseURL to succeed (fails on ssl param otherwise).
	if strings.Contains(m.Url, "ssl=true") {
		m.Url = strings.Replace(m.Url, "ssl=true", "", -1)
		useSSL = true
	}

	dialInfo, err = mgo.ParseURL(m.Url)
	dialInfo.Timeout = time.Second * 10

	// Use a dialer with TLS if secure connection desired.
	if useSSL {
		dialInfo.DialServer = func(addr *mgo.ServerAddr) (net.Conn, error) {
			return tls.Dial("tcp", addr.String(), &tls.Config{})
		}
	}

	// We always dial with info to support both SSL and non-SSL connections.
	sess, err = mgo.DialWithInfo(dialInfo)
	if err != nil {
		return util.NewWebError(http.StatusInternalServerError,
			"MH-100", "Can't connect to mongo").Add("original", err.Error())
	}

	if m.Log != nil {
		m.Log.Println("Connecting to mongo db " + m.DbName + ", collection " + m.CollName)
	}

	coll := sess.DB(m.DbName).C(m.CollName)
	m.Sess, m.Coll = sess, coll
	return m.Reconn.Reconnect(m)
}