Example #1
0
// Marshal a protobuf struct into a database thang.
func marshalDBT(dbt *C.DBT, val proto.Message) (err error) {
	buf, err := proto.Marshal(val)
	if err != nil {
		return
	}

	if len(buf) > 0 {
		dbt.data = unsafe.Pointer(&buf[0])
		dbt.size = C.u_int32_t(len(buf))
	} else {
		dbt.data = nil
		dbt.size = 0
	}

	return
}
Example #2
0
// Marshal the key of a record into a database thang.
func (db Database) marshalKey(dbt *C.DBT, rec proto.Message) (err error) {
	key := recordKey(rec)

	dbtype, err := db.Type()
	if err != nil {
		return
	}

	switch dbtype {
	case Numbered, Queue:
		dbt.data = unsafe.Pointer(key.(*uint32))
		dbt.size = 4

	default:
		err = marshalDBT(dbt, key.(proto.Message))
	}

	return
}
Example #3
0
// Retrieve the first record with matching key from the database. If
// exact is false, the first record with a key greater than or equal
// to the given one is fetched; this operation mode only makes sense
// in combination with a B-tree database.
func (cur Cursor) Set(rec proto.Message, exact bool) (err error) {
	var key, data C.DBT
	var flags C.u_int32_t = 0

	if exact {
		key.flags |= C.DB_DBT_READONLY
		flags |= C.DB_SET
	} else {
		key.flags |= C.DB_DBT_MALLOC
		flags |= C.DB_SET_RANGE
	}

	data.flags |= C.DB_DBT_REALLOC
	defer C.free(data.data)

	err = cur.db.marshalKey(&key, rec)
	if err == nil {
		odata := key.data
		defer func() {
			if key.data != odata {
				C.free(data.data)
			}
		}()
	} else {
		return
	}

	err = check(C.db_cursor_get(cur.ptr, &key, &data, flags))
	if err != nil {
		return
	}

	err = cur.db.unmarshalData(&data, rec)
	if err != nil {
		return
	}

	err = cur.db.unmarshalKey(&key, rec)
	return
}
Example #4
0
// Retrieve the previous record from the cursor.
func (cur Cursor) Prev(rec proto.Message) (err error) {
	var key, data C.DBT

	key.flags |= C.DB_DBT_REALLOC
	defer C.free(key.data)
	data.flags |= C.DB_DBT_REALLOC
	defer C.free(data.data)

	err = check(C.db_cursor_get(cur.ptr, &key, &data, C.DB_PREV))
	if err != nil {
		return
	}

	err = cur.db.unmarshalData(&data, rec)
	if err != nil {
		return
	}

	err = cur.db.unmarshalKey(&key, rec)

	return
}
Example #5
0
// Store records in the database. In combination with a queue or
// numbered database the append flags causes the keys of the records
// to be set to fresh record numbers, for any other database it
// prevents an existing record with the same key from being
// overwritten.
func (db Database) Put(txn Transaction, append bool, recs ...proto.Message) (err error) {
	dbtype, err := db.Type()
	if err != nil {
		return
	}

	var key, data C.DBT
	var flags C.u_int32_t = 0

	if append {
		key.flags |= C.DB_DBT_USERMEM

		switch dbtype {
		case Numbered, Queue:
			flags |= C.DB_APPEND
		default:
			flags |= C.DB_NOOVERWRITE
		}
	} else {
		key.flags |= C.DB_DBT_READONLY
	}

	data.flags |= C.DB_DBT_READONLY

	for _, rec := range recs {
		err = db.marshalData(&data, rec)
		if err != nil {
			return
		}

		err = db.marshalKey(&key, rec)
		if err == nil {
			key.ulen = key.size
		} else {
			return
		}

		err = check(C.db_put(db.ptr, txn.ptr, &key, &data, flags))
		if err != nil {
			return
		}
	}

	return
}
Example #6
0
// Get records from the database. The consume flag makes sense only in
// combination with a queue database and causes the operation to wait
// for and obtain the next enqueued record.
func (db Database) Get(txn Transaction, consume bool, recs ...proto.Message) (err error) {
	var key, data C.DBT
	var flags C.u_int32_t = 0

	if consume {
		key.flags |= C.DB_DBT_USERMEM
		flags |= C.DB_CONSUME_WAIT
	} else {
		key.flags |= C.DB_DBT_READONLY
	}

	data.flags |= C.DB_DBT_REALLOC
	defer C.free(data.data)

	for _, rec := range recs {
		err = db.marshalKey(&key, rec)
		if err == nil {
			key.ulen = key.size
		} else {
			return
		}

		err = check(C.db_get(db.ptr, txn.ptr, &key, &data, flags))
		if err != nil {
			return
		}

		err = db.unmarshalData(&data, rec)
		if err != nil {
			return
		}

		err = db.unmarshalKey(&key, rec)
		if err != nil {
			return
		}
	}

	return
}
Example #7
-1
// Delete records from the database.
func (db Database) Del(txn Transaction, recs ...proto.Message) (err error) {
	var key C.DBT

	key.flags |= C.DB_DBT_READONLY

	for _, rec := range recs {
		err = db.marshalKey(&key, rec)
		if err != nil {
			return
		}

		err = check(C.db_del(db.ptr, txn.ptr, &key, 0))
		if err != nil {
			return
		}
	}

	return
}