func (bs *BlobStore) keyExistsInDb(id *int64, key pandora.Key) (bool, error) { err := bs.conn.QueryRow("select id from pgstore_blobs_ref where blobid = $1", key.Bytes()).Scan(id) if err == sql.ErrNoRows { return false, nil } else { if err != nil { return false, err } } return *id > 0, nil }
// PutData write the contents of data and return the key used to store the data func (bs *BlobStore) PutData(k pandora.Key, data []byte) (pandora.Key, error) { kw := pandora.SHA1KeyWriter{} kw.Write(data) actual := kw.Key() if k != nil && len(k.Bytes()) >= len(actual.Bytes()) { // avoid allocating outside the stack copy(k.Bytes(), actual.Bytes()) } else { // use the heap k = actual } err := bs.insert(k, data) return k, err }
func (ms *MessageStore) Ack(mid, lid pandora.Key, status pandora.AckStatus) error { return doInsideTransaction(ms.conn, func(tx querier) error { var id int64 switch status { case pandora.StatusConfirmed, pandora.StatusRejected: default: return pandora.ErrUnableToChangeStatus } err := tx.QueryRow(`update pgstore_messages set status = $1, lid = null, leaseuntil = null where mid = $2 and lid = $3 and leaseuntil >= $4 returning id`, status, mid.Bytes(), lid.Bytes(), time.Now()).Scan(&id) if err != nil { return err } if id == 0 { return pandora.ErrUnableToChangeStatus } return nil }) }
// if data have a Bytes() []byte method, then it is used instead of a copy func (bs *BlobStore) insert(out pandora.Key, data []byte) error { var id int64 var err error exists, err := bs.keyExistsInDb(&id, out) if err != nil { return err } if exists { return nil } return doInsideTransaction(bs.conn, func(tx querier) error { err := tx.QueryRow(`insert into pgstore_blobs(blobid, data) values ($1, $2) returning id`, out.Bytes(), data).Scan(&id) if err != nil { return err } _, err = tx.Exec(`insert into pgstore_blobs_ref(id, blobid, delta) values ($1, $2, $3)`, id, out.Bytes(), 0) if err != nil { return err } return err }) }
func (bs *BlobStore) UpdateRefCount(k pandora.Key, delta int) error { var err error var id int64 exists, err := bs.keyExistsInDb(&id, k) if !exists { return ErrKeyNotFound } _, err = bs.conn.Exec(`insert into pgstore_blobs_ref(id, blobid, delta) values ($1, $2, $3)`, id, k.Bytes(), delta) return err }
// GetData read the contents stored under the k key func (bs *BlobStore) GetData(out []byte, k pandora.Key) ([]byte, error) { var id int64 var size int var err error exists, err := bs.keyExistsInDb(&id, k) if !exists { return nil, ErrKeyNotFound } err = bs.conn.QueryRow(`select bs.id, octet_length(bs.data) from pgstore_blobs bs where bs.blobid = $1`, k.Bytes()).Scan(&id, &size) if err != nil { return nil, err } out = sliceOfSize(out, size) err = bs.conn.QueryRow(`select bs.data from pgstore_blobs bs where bs.id = $1`, id).Scan(&out) return out, err }