def read_many(self, start_sequence, min_count, max_count): """Reads a batch of items from the Ringbuffer. If the number of available items after the first read item is smaller than the max_count, these items are returned. So it could be the number of items read is smaller than the max_count. If there are less items available than min_count, then this call blocks. Reading a batch of items is likely to perform better because less overhead is involved. Args: start_sequence (int): The start_sequence of the first item to read. min_count (int): The minimum number of items to read. max_count (int): The maximum number of items to read. Returns: hazelcast.future.Future[list]: The list of read items. """ check_not_negative(start_sequence, "sequence can't be smaller than 0") check_true(max_count >= min_count, "max count should be greater or equal to min count") check_true(max_count < MAX_BATCH_SIZE, "max count can't be greater than %d" % MAX_BATCH_SIZE) future = Future() request = ringbuffer_read_many_codec.encode_request( self.name, start_sequence, min_count, max_count, None) def handler(message): return ImmutableLazyDataList( ringbuffer_read_many_codec.decode_response(message)["items"], self._to_object) def check_capacity(capacity): try: capacity = capacity.result() check_true( min_count <= capacity, "min count: %d should be smaller or equal to capacity: %d" % (min_count, capacity), ) f = self._invoke(request, handler) f.add_done_callback(set_result) except Exception as e: future.set_exception(e) def set_result(f): try: future.set_result(f.result()) except Exception as e: future.set_exception(e) self.capacity().add_done_callback(check_capacity) return future
def read_many( self, start_sequence: int, min_count: int, max_count: int, filter: typing.Any = None ) -> Future[ReadResult]: """Reads a batch of items from the Ringbuffer. If the number of available items after the first read item is smaller than the ``max_count``, these items are returned. So it could be the number of items read is smaller than the ``max_count``. If there are less items available than ``min_count``, then this call blocks. Warnings: These blocking calls consume server memory and if there are many calls, it can be possible to see leaking memory or ``OutOfMemoryError`` s on the server. Reading a batch of items is likely to perform better because less overhead is involved. A filter can be provided to only select items that need to be read. If the filter is ``None``, all items are read. If the filter is not ``None``, only items where the filter function returns true are returned. Using filters is a good way to prevent getting items that are of no value to the receiver. This reduces the amount of IO and the number of operations being executed, and can result in a significant performance improvement. Note that, filtering logic must be defined on the server-side. If the ``start_sequence`` is smaller than the smallest sequence still available in the Ringbuffer (:func:`head_sequence`), then the smallest available sequence will be used as the start sequence and the minimum/maximum number of items will be attempted to be read from there on. If the ``start_sequence`` is bigger than the last available sequence in the Ringbuffer (:func:`tail_sequence`), then the last available sequence plus one will be used as the start sequence and the call will block until further items become available and it can read at least the minimum number of items. Args: start_sequence: The start sequence of the first item to read. min_count: The minimum number of items to read. max_count: The maximum number of items to read. filter: Filter to select returned elements. Returns: The list of read items. """ check_not_negative(start_sequence, "sequence can't be smaller than 0") check_not_negative(min_count, "min count can't be smaller than 0") check_true(max_count >= min_count, "max count should be greater or equal to min count") check_true( max_count < MAX_BATCH_SIZE, "max count can't be greater than %d" % MAX_BATCH_SIZE ) try: filter_data = self._to_data(filter) except SchemaNotReplicatedError as e: return self._send_schema_and_retry( e, self.read_many, start_sequence, min_count, max_count, filter ) request = ringbuffer_read_many_codec.encode_request( self.name, start_sequence, min_count, max_count, filter_data ) def handler(message): response = ringbuffer_read_many_codec.decode_response(message) read_count = response["read_count"] next_seq = response["next_seq"] items = response["items"] item_seqs = response["item_seqs"] return ReadResult(read_count, next_seq, items, item_seqs, self._to_object) def continuation(future): # Since the first call to capacity # is cached on the client-side, doing # a capacity check each time should not # be a problem capacity = future.result() check_true( max_count <= capacity, "max count: %d should be smaller or equal to capacity: %d" % (max_count, capacity), ) return self._invoke(request, handler) return self.capacity().continue_with(continuation)