331529fc94
* add an Aerospike storage backend * go mod vendor * add Aerospike storage configuration docs * review fixes * bump aerospike client to v3.1.1 * rename the defaultHostname variable * relocate the docs page
160 lines
4.7 KiB
Go
160 lines
4.7 KiB
Go
// Copyright 2013-2020 Aerospike, Inc.
|
|
//
|
|
// 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 aerospike
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
|
|
. "github.com/aerospike/aerospike-client-go/types"
|
|
Buffer "github.com/aerospike/aerospike-client-go/utils/buffer"
|
|
)
|
|
|
|
// Key is the unique record identifier. Records can be identified using a specified namespace,
|
|
// an optional set name, and a user defined key which must be unique within a set.
|
|
// Records can also be identified by namespace/digest which is the combination used
|
|
// on the server.
|
|
type Key struct {
|
|
// namespace. Equivalent to database name.
|
|
namespace string
|
|
|
|
// Optional set name. Equivalent to database table.
|
|
setName string
|
|
|
|
// Unique server hash value generated from set name and user key.
|
|
digest [20]byte
|
|
|
|
// Original user key. This key is immediately converted to a hash digest.
|
|
// This key is not used or returned by the server by default. If the user key needs
|
|
// to persist on the server, use one of the following methods:
|
|
//
|
|
// Set "WritePolicy.sendKey" to true. In this case, the key will be sent to the server for storage on writes
|
|
// and retrieved on multi-record scans and queries.
|
|
// Explicitly store and retrieve the key in a bin.
|
|
userKey Value
|
|
|
|
keyWriter keyWriter
|
|
}
|
|
|
|
// Namespace returns key's namespace.
|
|
func (ky *Key) Namespace() string {
|
|
return ky.namespace
|
|
}
|
|
|
|
// SetName returns key's set name.
|
|
func (ky *Key) SetName() string {
|
|
return ky.setName
|
|
}
|
|
|
|
// Value returns key's value.
|
|
func (ky *Key) Value() Value {
|
|
return ky.userKey
|
|
}
|
|
|
|
// SetValue sets the Key's value and recompute's its digest without allocating new memory.
|
|
// This allows the keys to be reusable.
|
|
func (ky *Key) SetValue(val Value) error {
|
|
ky.userKey = val
|
|
return ky.computeDigest()
|
|
}
|
|
|
|
// Digest returns key digest.
|
|
func (ky *Key) Digest() []byte {
|
|
return ky.digest[:]
|
|
}
|
|
|
|
// Equals uses key digests to compare key equality.
|
|
func (ky *Key) Equals(other *Key) bool {
|
|
return bytes.Equal(ky.digest[:], other.digest[:])
|
|
}
|
|
|
|
// String implements Stringer interface and returns string representation of key.
|
|
func (ky *Key) String() string {
|
|
if ky == nil {
|
|
return ""
|
|
}
|
|
|
|
if ky.userKey != nil {
|
|
return fmt.Sprintf("%s:%s:%s:%v", ky.namespace, ky.setName, ky.userKey.String(), Buffer.BytesToHexString(ky.digest[:]))
|
|
}
|
|
return fmt.Sprintf("%s:%s::%v", ky.namespace, ky.setName, Buffer.BytesToHexString(ky.digest[:]))
|
|
}
|
|
|
|
// NewKey initializes a key from namespace, optional set name and user key.
|
|
// The set name and user defined key are converted to a digest before sending to the server.
|
|
// The server handles record identifiers by digest only.
|
|
func NewKey(namespace string, setName string, key interface{}) (*Key, error) {
|
|
newKey := &Key{
|
|
namespace: namespace,
|
|
setName: setName,
|
|
userKey: NewValue(key),
|
|
}
|
|
|
|
if err := newKey.computeDigest(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return newKey, nil
|
|
}
|
|
|
|
// NewKeyWithDigest initializes a key from namespace, optional set name and user key.
|
|
// The server handles record identifiers by digest only.
|
|
func NewKeyWithDigest(namespace string, setName string, key interface{}, digest []byte) (*Key, error) {
|
|
newKey := &Key{
|
|
namespace: namespace,
|
|
setName: setName,
|
|
userKey: NewValue(key),
|
|
}
|
|
|
|
if err := newKey.SetDigest(digest); err != nil {
|
|
return nil, err
|
|
}
|
|
return newKey, nil
|
|
}
|
|
|
|
// SetDigest sets a custom hash
|
|
func (ky *Key) SetDigest(digest []byte) error {
|
|
if len(digest) != 20 {
|
|
return NewAerospikeError(PARAMETER_ERROR, "Invalid digest: Digest is required to be exactly 20 bytes.")
|
|
}
|
|
copy(ky.digest[:], digest)
|
|
return nil
|
|
}
|
|
|
|
// Generate unique server hash value from set name, key type and user defined key.
|
|
// The hash function is RIPEMD-160 (a 160 bit hash).
|
|
func (ky *Key) computeDigest() error {
|
|
// With custom changes to the ripemd160 package,
|
|
// now the following line does not allocate on the heap anymore/.
|
|
ky.keyWriter.hash.Reset()
|
|
|
|
if _, err := ky.keyWriter.Write([]byte(ky.setName)); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := ky.keyWriter.Write([]byte{byte(ky.userKey.GetType())}); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := ky.keyWriter.writeKey(ky.userKey); err != nil {
|
|
return err
|
|
}
|
|
|
|
// With custom changes to the ripemd160 package,
|
|
// the following line does not allocate on he heap anymore.
|
|
ky.keyWriter.hash.Sum(ky.digest[:])
|
|
return nil
|
|
}
|