Operations on Keys
You can use options in some space operations in order to do two things:
- Optimize response times and resource usage by:
- Combining operations
- You can do a put plus a lock or unlock operation in a single call and possibly in half the time if you do a put with a lock or unlock option set.
- These two operations are executed atomically as well.
- For example, doing a transactional update on a record is usually implemented by a lock followed by a get, followed by a put and an unlock: this can be done with ActiveSpaces in two operations:
- A lock (without the forget option set) returns the tuple that is stored at the key that gets locked.
- A put with the unlock option set (and the forget option set because you do not care to receive the old value you are updating back from the space) does the update and clears the lock.
- Indicating that you do not care to capture what the space operation would normally return
- A put operation normally returns the record that was overwritten (if any) from the space. Set the forget option for your put to save some resources by indicating that you do not care to receive this old value back.
- To clear a record in a space, use a take operation with the forget option set.
- A lock operation normally returns the record stored in the space at the key that was locked (essentially a get and lock). Set the forget option if you not care to get this value from the space.
- Override some space definition settings for the record being written in the space or the operation:
- Set a specific TTL for a record being put in the space
- LockWait time for the put, lock , unlock
Batch and Asynchronous Operations
Space operations are by default execute synchronously:
- If your application is a leech, this means that read and write operations will always require at least one network round trip of latency before returning.
- If your application is a seeder, the greater the number of seeders on the space the greater the chance that a write operation will require a network round trip to execute.
- At current network speeds, the network round trip time can make up for 90% of the latency of execution of an operation
- Even the “loopback interface” can experience large variations in network latency and can sometimes average to a time equivalent to that of 1 Gigabit Ethernet networks (though the loopback interface is usually pretty “high bandwidth’).
- The network round trip is therefore usually what has the greatest effect on the latency of each space call returning, and if the application is going back-to-back individual space operations a direct impact on its throughput (the number of operations per second that the space can execute).
You can get higher throughput by parallelizing operations over the space(s) using one of the following methods:
- Batch operations (putAll, getAll, takeAll, and so on) should be used when you need to execute more than one operation of the same type on a single space.
- For example, rather than doing “puts in a loop,” use putAll.
- Remember that operations in a batch are executed in no particular order!
- Asynchronous operations return as soon as the request is sent over the network, without waiting for an answer or acknowledgement from the node the request was sent to.
- You can use asynchronous operations to parallelize a bunch of operations on a bunch of spaces.
- Consider using asynchronous operations when doing “writes,” since your application logic may not care about the returned values from write operations.
- You can combine asynchronous operations with batch operations (doing asynchronous batch operations).
Browsers and Listeners
Browser prefetch can have a very large impact on performance: use the largest prefetch value (up to “-1”which means prefetch everything) you can afford in order to get the best performance out of your browsers.
It is better (more efficient) to register a single listener that has handlers for all types of events than to register multiple listeners each having only a handler for one kind of events.
Get, take, lock, unlock and invoke
Take and lock:
- The take and lock operations also do an implicit “get ”since they both return the tuple (if any) stored at the key that was just cleared or locked
- This makes the take operation a “consume” operation: if two processes try to “take” the same key at the same time you have a guarantee that only one of them will be able to take the tuple.
- Remember you can create “take browsers” and “lock browsers” as well as the default “get browsers’.
- When a process leaves (gracefully or not) the metaspace, all the locks it had created are automatically cleared.
- If a space has a lock scope of process, all threads in the process share the lock.
- However, be careful that the scope of transactions remains a thread; therefore any writes in a pending transaction would mean that an attempt to unlock any of the keys in question could fail, or block until the transaction commits or rolls back, depending on the space’s LockWait.
- You can control this behavior by using a LockWait option with the unlock operation.
- If you assume your locks will be transient and don’t want to have to implement retry logic in your code, you can leverage the space’s LockWait attribute to have locking operations automatically block until they can acquire the lock.
- However, if you combine a LockWait value of “forever” with a LockTTL value of “forever,” you might create deadlock situations,
- Transactions can span as many spaces as you want, but are limited to a single Metaspace.
- When a process leaves (gracefully or not) the Metaspace, any of its pending transactions are automatically rolled back.
Space operations within a transaction are effectively prepared when the operation is invoked: if all your space operations invoked after you called beginTransaction executed without an error then you can safely call Commit, otherwise you should call Rollback.
You can adjust the scope of the transaction from “thread” to “process” and you can pass a transaction context from one thread to another.