Skip to main content

API Changes

Version 11.0.1

[CLIENT-2267] Revert adding base64 methods to aerospike module

These methods have been removed from the aerospike module due to memory errors when they are called:

  1. aerospike.get_expression_base64()
  2. aerospike.get_cdtctx_base64()

Course of action:

Call these methods from a client instance instead of the aerospike module. Assuming client is an instance of aerospike.Client, the above calls should be replaced by:

  1. client.get_expression_base64()
  2. client.get_cdtctx_base64()

Version 11.0.0

[CLIENT-701] Batch methods: stop accepting a tuple of keys and bins

For the following functions:

  • client.get_many()
  • client.exists_many()

The keys parameter no longer takes in a tuple of keys. It only takes in a list of keys.

In addition, client.select_many() no longer takes in a tuple for the keys and bins parameters. Those parameters only take in a list of keys and bins, respectively.

Course of action:

Change code such as this:

keys = (("test", "demo", 1), ("test", "demo", 2))
bins = ("bin1", "bin2")
client.select_many(keys, bins)

...to this instead:

keys = [("test", "demo", 1), ("test", "demo", 2)]
bins = ["bin1", "bin2"]
client.select_many(keys, bins)

[CLIENT-2144] Expressions: add support for comparing KeyOrderedDicts (new server feature)

Before server 6.3, it is possible to compare maps in expressions if the maps were nested inside a list. For example, this code would work before server 6.3:

from aerospike_helpers.expressions import base as expr

client.put(key, {"bin": [{"a": 1}]})
exp = expr.Eq(expr.ListBin("bin"), [{"a": 1}]).compile()
record = client.get(key, {"expressions": exp})
print(record[2])
# {'bin': [{'a': 1}]}

This is now unsupported in server 6.3 because comparing unordered maps can potentially lead to inconsistent results. However, it is possible in server 6.3 to compare key-ordered maps in expressions.

Course of action:

For those using a server version < 6.3, no action is necessary. But it is recommended not to compare unordered maps in expressions.

For those upgrading to server 6.3, maps stored in the server must be key-ordered in order to be compared against in expressions. If the maps in the server are already key-ordered, and you would like to compare them in expressions, you must wrap any dictionaries in expressions with the KeyOrderedDict class.

For example, the code above must store the map as a key ordered map before comparing it in an expression:

from aerospike_helpers.expressions import base as expr
from aerospike import KeyOrderedDict

client.put(key, {"bin": [KeyOrderedDict({"a": 1})]})
exp = expr.Eq(expr.ListBin("bin"), [KeyOrderedDict({"a": 1})]).compile()
record = client.get(key, {"expressions": exp})
print(record[2])
# {'bin': [{'a': 1}]}

[CLIENT-2197] Return AEROSPIKE_ERR_NAMESPACE_NOT_FOUND instead of AEROSPIKE_ERR_CLIENT when a namespace cannot be found

Course of action: Change code such as this:

from aerospike import exception as exc
key = ("nonexistent_namespace", "demo", 1)
try:
client.get(key)
except exc.ClientError:
print("Incorrect namespace")

...to this instead:

from aerospike import exception as exc
key = ("nonexistent_namespace", "demo", 1)
try:
client.get(key)
except exc.NamespaceNotFound:
print("Incorrect namespace")

[CLIENT-2143] Return last error code received when scan/query maxRetries is exceeded

When running a query or scan, if max_retries is exceeded, the transaction will return the last suberror that was received instead of a MaxRetriesExceeded error. For example, if you try to run a query on a non-indexed bin, the client will return an IndexNotFound error from the last attempt to query the bin.

This code will no longer work:

query = client.query("test", "demo")
query.select("bin_without_index")
query.where(p.equals("bin_without_index", 1))
def callback(input_tuple):
pass

try:
query.foreach(callback)
except exc.MaxRetriesExceeded:
print("Query failed")

Course of action:

When handling a MaxRetriesExceeded exception, change it to the exact error that is expected to get thrown during the last query attempt. In this case, it is an IndexNotFound error:

try:
query.foreach(callback)
except exc.IndexNotFound:
print("Query failed")

Version 10.0.0

[CLIENT-1989] get_cdtctx_base64(): take in context directly instead of a dictionary.

When passing in a context array to get_cdtctx_base64(), you must to pass it in directly as a parameter instead of embedding it in a dictionary.

This change is to make the API more easy to use and consistent with the other API methods.

Course of action:

This code:

get_cdtctx_base64({'ctx': ctx})

should be changed to:

get_cdtctx_base64(ctx)

Version 9.0.0

[CLIENT-2074] Change default send_bool_as constant to AS_BOOL

By default, the client now sends the boolean as an Aerospike server boolean type (aerospike.AS_BOOL) instead of a Python boolean type (aerospike.PY_BYTES).

For developers using server 5.6 and later

The server encodes Python booleans as the "blob" type and server booleans as the "booleans" type. Because of the ordering of types in a Collection Data Type (CDT), this may break rank operations for CDTs that store a mix of booleans and other types of values.

Course of action: Check that rank operations on CDTs containing both boolean and integers are handled properly.

For developers using server version earlier than 5.6

The server will fail to perform the write operation if the client uses the default send_bool_as value, aerospike.AS_BOOL, to write a boolean value to the server.

Course of actions:

  1. Change the default send_bool_as to a value other than aerospike.AS_BOOL.
  2. Upgrade the server to version 5.6 to support server-native boolean types.

[CLIENT-2008] batch_get_ops(): Remove meta field

batch_get_ops() previously had this function signature:

batch_get_ops(keys, ops[, meta, policy: dict]) → [key, meta, bins]

Now the meta parameter has been removed:

batch_get_ops(keys, ops[, policy: dict]) → [key, meta, bins]

[CLIENT-2012] scan_apply(): Report correct error value and message if scan wait fails

When scan_apply() is called and it internally calls scan_wait() and fails, it previously returned this error:

"error": "(-2, 'Unable to perform scan_wait on the scan', 'src/main/client/scan.c', 215, False)"

Now it returns an error from scan_wait() directly in order to identify the cause of the error.

Version 8.0.0

Connect when calling client constructor and conditionally no-op connect()

  • Calling the aerospike.Client constructor establishes the connection.
    • If user authentication is required, pass in a username and password in the client configuration dictionary by using the keys "username" and "password".
  • aerospike.Client.connect() only runs if the connection was closed by calling close() beforehand. Otherwise, using connect() does nothing.

Before version 8.0.0:

config = {
'hosts': hosts,
'policies': {'auth_mode': aerospike.AUTH_INTERNAL},
}
client = aerospike.client(config)
client.connect(user, password)

At version 8.0.0:

config = {
'hosts': hosts,
'policies': {'auth_mode': aerospike.AUTH_INTERNAL},
'user': user,
'password': password
}
client = aerospike.client(config)
# following is no-op
client.connect(user, password)

Having the client connect to the server when the constructor is called makes the Python client's behavior more consistent with our other clients, and it also removes the possibility of an application trying to perform server operations with the client without a connection.

If you are using a try/except block and have the constructor call outside of the try block, move the constructor call into the try block. If an exception happens, it would be coming from the constructor and not the connect() method.

This line of code:

client = aerospike.client(config).connect()

should not have an issue.

But code such as this:

client = aerospike.client(config)
try:
client.connect()
except Exception:
# eat exception and do something

Should be changed to this instead:

try:
client = aerospike.client(config)
except Exception:
# eat exception and do something

Version 7.0.0

Remove old predexp

Old predexp functionality has been removed. Code using old predexp must be converted to the new expression syntax. See: predexp to expression

Removed support for Debian 8

Debian 8 has reached its end of life. Python client installs on debian 8 may fail.

IndexNotFound and IndexNotReadable errors can now trigger retries

Previously these errors would cause transactions to fail immediately. Now they trigger retries if that transaction's policy allows for them. If your application uses transactions with retries and checks for the IndexNotFound or IndexNotReadable errors, switch to checking for the MaxRetriesExceeded error instead.

Bytes blobs read from the database will now be read as bytes instead of bytearray

Bytes and Bytearray objects written by the Python client to Aerospike are stored on the server as bytes blobs. Previously, these bytes blobs were always read as bytearrays. When bytes were written as dictionary keys, they would be read as bytearrays causing an unhashable key error. If your application reads bytes blobs and type checks the result expecting bytearray, the expected type should change to bytes. If your application relies on bytearray results being mutable and encounters errors like "TypeError: 'bytes' object does not support item assignment" the result has probably switched to bytes. bytes objects are not mutable so should not be directly modified."

Query policies max_records and records_per_second are now fields of the Query class

Query policies max_records and records_per_second have been moved from the query policy to be fields of the Query class. max_records and records_per_second policies will be ignored, so if your code uses them, change to Query.max_records and Query.records_per_second instead.

Version 7.0.0 - Replace predicate expressions with Aerospike expressions

The old predexp functionality has been replaced by Expressions. Expressions include all previous predicate expression functionality (with a different, improved syntax) plus support for record metadata expressions and list/map/bit/hyperloglog expression methods analogous to those used in operations.

See the Python client expressions documentation for more details.

Use of the new expressions API require server version 5.2.0.4 or later. Convert code using old predexp to the new syntax. Here is an example:

import aerospike
from aerospike_helpers import expressions as exp
from aerospike import predexp

# (c >= 11 and c <= 20) or (d >= 3 and d <= 5)
# Using old removed predexp.
predexps = [
predexp.integer_bin("c"),
predexp.integer_value(11),
predexp.integer_greatereq(),
predexp.integer_bin("c"),
predexp.integer_value(20),
predexp.integer_lesseq(),
predexp.predexp_and(2)
predexp.integer_bin("d"),
predexp.integer_value(3),
predexp.integer_greatereq(),
predexp.integer_bin("d"),
predexp.integer_value(5),
predexp.integer_lesseq(),
predexp.predexp_and(2),
predexp.predexp_or(2)
]

# Converted to new expressions.
expression = exp.Or(
exp.And(
exp.GE(exp.IntBin("c"), 11),
exp.LE(exp.IntBin("c"), 20)
),
exp.And(
exp.GE(exp.IntBin("d"), 3),
exp.LE(exp.IntBin("d"), 5)
)
).compile()

Version 6.0.0

Info_node() no longer works when security is enabled

  • Because of changes in client authentication internals in C client 5.2.0, info_node() will fail if used when authentication is enabled. Checkout info_single_node() for a replacement.

Dropped support for scan/query options percent, priority, fail_on_cluster_change

  • These options have been dropped and are no longer sent to the server. They will need to be removed from application code.

Dropped support for CentOS 6 and Ubuntu 16.04

  • CentOS 6 and Ubuntu 16.04 have reached their support end of life. Aerospike Python client installs on CentOS6 and Ubuntu 16.04 will fail.

Python 3.5 Support Discontinued

  • Python 3.5 has reached end of life. The Aerospike Python client will no longer be distributed for Python 3.5.

Version 5.0.0

Aerospike Server 4.9 and up Required

  • Aerospike Python client 5.0.0 requires Aerospike server 4.9 or later. Attemping to connect to a server older than 4.9 will yield the error "-10, Failed to connect".

Python 2.7 and 3.4 Support Discontinued

  • Python 2.7 and 3.4 have reached end of life. The Aerospike Python client will no longer be distributed for them.

Version 4.0.0

Scan policy changes

  • Policy key fail_on_cluster_change has no effect for Aerospike server versions >= 4.9.

Scan option changes

  • Option key percent no longer accepts 0 as a valid percent.

Version 3.7.0

Read Consistency Level Changes

Read policy changes for transactions involving AP (availability) namespaces

  • Policy key consistency_level was replaced by read_mode_ap for the read, batch and, operate policies.
    • POLICY_CONSISTENCY_ALL was replaced by POLICY_READ_MODE_AP_ALL
    • POLICY_CONSISTENCY_ONE was replaced by POLICY_READ_MODE_AP_ONE

Read policy changes for transactions involving SC (strong consistency) namespaces

  • Policy key linearize_read was replaced by read_mode_sc for the read, batch, and operate policies. Added aerospike.POLICY_READ_MODE_SC_SESSION, aerospike.POLICY_READ_MODE_SC_LINEARIZE, aerospike.POLICY_READ_MODE_SC_ALLOW_REPLICA, and aerospike.POLICY_READ_MODE_SC_ALLOW_UNAVAILABLE as options for this key.

Version 3.6.0

Backwards Incompatible API changes

Shared memory layout change

Shared memory layout has changed, and accordingly the default SHM key has changed from 0xA7000000 to 0xA8000000. If manually specifiying an SHM key, it is crucial to ensure that a separate key is used in order to prevent this version's client from sharing memory with a previous version.

Removed Unused Exceptions

The BinExistsError, BinNotFound exceptions have been removed.

Version 3.2.0

Additional Features

  • Updated to C client 4.3.11
  • Added client.map_get_by_value_list and client.map_get_by_key_list These methods require Aerospike Server version >= 3.16.0.1 .

Version 3.1.0

Additional Features

  • Updated to C client 4.3.6
  • Added exists policy field to operate policies

Backwards Incompatible API changes

  • Updated the args passed to AerospikeError constructor internally to contain 5 arguments. The arguments previously were error code, error message, error file, error line. A fifth argument in_doubt has been added to the internal calls. so the arguments passed to the constructor are now : error_code, error_message, error_file, error_line, in_doubt

    This means that code such as the following will now raise a ValueError

try:
client.get(key)
except AerospikeError as e:
code, msg, file, line = e.args
print(code, msg, file, line)

This can be fixed by unpacking the fifth value from the Error's args tuple

try:
client.get(key)
except AerospikeError as e:
code, msg, file, line, in_doubt = e.args
print(code, msg, file, line)

Version 3.0.0

Additional Features

  • Updated to C client 4.3.1
  • Added a new list increment operation OP_LIST_INCREMENT . It can be used to increase an element of a list by a provided amount.
  • Added the option to specify a specific node to run on a scan on, via a new optional nodename parameter.
  • Added the option to specify that Query.results and Query.foreach should not return bins, via a new optional parameter options to both methods.
  • Added aerospike.info_all() to allow sending of an info command to all nodes in the current cluster.
  • Added linearize_read option to read policies. Requires Enterprise server >= 4.0.0

Deprecations

  • client#info has been deprecated. In order to send requests to the entire cluster, the new method client#info_all should be used. In order to send requests to hosts specified in a list, we recommend a loop invoking multiple calls to aerospike.info_node. See below for an example implementation:

def info_to_host_list(client, request, hosts, policy=None):
output = {}
for host in hosts:
try:
response = client.info_node(request, host, policy)
output[host] = response
except Exception as e:
# Handle the error gracefully here
output[host] = e
return output
  • Setting of global policy defaults via top level entries in the 'policies' dictionary in the constructor config dict has been deprecated. See the constructor documentation for the new recommended method of specifying defaults.

Backwards Incompatible API changes

LDT Removal

Removed LDT (client#llist) methods and support. Server version 3.14 is the last version of the Aerospike server to support the functionality.

Index Methods

  • Methods which create indexes, ( index_string_create, index_integer_create, index_list_create, index_map_keys_create, index_map_values_create and, index_geo2dsphere_create ), will now raise an IndexFoundError if the specified bin has already been indexed, or if an index with the same name already exists.

  • Methods which drop indexes (index_remove), will now raise an IndexNotFound if the named index does not exist.

Shared memory layout change

Shared memory layout has changed, and accordingly the default SHM key has changed from 0xA6000000 to 0xA7000000 . If manually specifiying an SHM key, it is crucial to ensure that a separate key is used in order to prevent this version's client from sharing memory with a previous version.

Changed and removed policy field names:

In all policies, (except for info and admin), timeout has been split into total_timeout and socket_timeout total_timeout is an int representing total transaction timeout in milliseconds. The total_timeout is tracked on the client and sent to the server along with the transaction in the wire protocol. The client will most likely timeout first, but the server also has the capability to timeout the transaction. If total_timeout is not zero and total_timeout is reached before the transaction completes, the transaction will return error TimeoutError. If total_timeout is zero, there will be no total time limit. See the documentation for individual policies for the default values.

socket_timeout is an int representing socket idle timeout in milliseconds when processing a database command. If socket_timeout is not zero and the socket has been idle for at least socket_timeout, both max_retries and total_timeout are checked. If max_retries and total_timeout are not exceeded, the transaction is retried. If both socket_timeout and total_timeout are non-zero and socket_timeout > total_timeout, then socket_timeout will be set to total_timeout. If socket_timeout is zero, there will be no socket idle limit. See the documentation for individual policies for the default values.

retry has beeen removed.

max_retries has been added, it is an integer specifying the number of times a transaction should be retried before aborting. If max_retries is exceeded, TimeoutError will be raised.

WARNING: Database writes that are not idempotent (such as client#increment) should not be retried because the write operation may be performed multiple times if the client timed out previous transaction attempts. It’s important to use a distinct write policy for non-idempotent writes which sets max_retries = 0;

The default value for max_retries is 2.

Changes in policy defaults for aerospike.client constructor

In this version, individual config dictionaries (read, write, apply, operate, scan, query, batch, remove) for method types should be used inside of the top level policies dictionary for setting policies. In previous versions, individual policies were set at the top level policies dictionary rather than in per method type dictionaries. The type of policy which affects each method can be found in the documenation. See the main documentation for the keys and values available for these new configuration dictionaries. See below for an example of the change in constructor usage:

#  Pre Python client 3.0.0

hosts = [('localhost', 3000)]

timeout = 2345
key_policy = aerospike.POLICY_KEY_SEND

# This changes defaults for all methods, requiring a config dictionary to be passed in to all methods which
# should use different values.
policies = {timeout': timeout, 'key': key_policy, 'retry': aerospike.POLICY_RETRY_ONCE}
config = {'hosts': hosts, 'policies': policies}

client = aerospike.client(config)
#  Post Python client 3.0.0

hosts = [('localhost', 3000)]

write_total_timeout = 4321
read_total_timeout = 1234
write_key_policy = aerospike.POLICY_KEY_SEND

read_policy = {'total_timeout': read_total_timeout, 'max_retries': 1}
write_policy = {'total_timeout': write_total_timeout, 'key': write_key_policy, 'max_retries': 1}

# operate policies affect methods such as client#increment, so these should not be retried since they are not idempotent.
operate_policy = {'max_retries': 0}

# Change the defaults for read, write, and operate methods, all other methods will use builtin defaults.
policies = {'read': read_policy, 'write': write_policy, 'operate': operate_policy}

config = {'hosts': hosts, 'policies': policies}

client = aerospike.client(config)