Beispiel #1
0
        /**
         * Put a record asynchronously. A {@link ListenableFuture} is returned that
         * can be used to retrieve the result, either by polling or by registering a
         * callback.
         *
         * <p>            * The return value can be disregarded if you do not wish to process the
         * result. Under the covers, the KPL will automatically reattempt puts in
         * case of transient errors (including throttling). A failed result is
         * generally returned only if an irrecoverable error is detected (e.g.
         * trying to put to a stream that doesn't exist), or if the record expires.
         *
         * <p>
         * <b>Thread safe.</b>
         *
         * <p>
         * To add a listener to the future:
         * <p>
         * <code>
         * ListenableFuture&lt;PutRecordResult&gt; f = myKinesisProducer.addUserRecord(...);
         * com.google.common.util.concurrent.Futures.addCallback(f, callback, executor);
         * </code>
         * <p>
         * where <code>callback</code> is an instance of
         * {@link com.google.common.util.concurrent.FutureCallback} and
         * <code>executor</code> is an instance of
         * {@link java.util.concurrent.Executor}.
         * <p>
         * <b>Important:</b>
         * <p>
         * If long-running tasks are performed in the callbacks, it is recommended
         * that a custom executor be provided when registering callbacks to ensure
         * that there are enough threads to achieve the desired level of
         * parallelism. By default, the KPL will use an internal thread pool to
         * execute callbacks, but this pool may not have a sufficient number of
         * threads if a large number is desired.
         * <p>
         * Another option would be to hand the result off to a different component
         * for processing and keep the callback routine fast.
         *
         * @param stream
         *            Stream to put to.
         * @param partitionKey
         *            Partition key. Length must be at least one, and at most 256
         *            (inclusive).
         * @param explicitHashKey
         *            The hash value used to explicitly determine the shard the data
         *            record is assigned to by overriding the partition key hash.
         *            Must be a valid string representation of a positive integer
         *            with value between 0 and <tt>2^128 - 1</tt> (inclusive).
         * @param data
         *            Binary data of the record. Maximum size 1MiB.
         * @return A future for the result of the put.
         * @throws IllegalArgumentException
         *             if input does not meet stated constraints
         * @throws DaemonException
         *             if the child process is dead
         * @see ListenableFuture
         * @see UserRecordResult
         * @see KinesisProducerConfiguration#setRecordTtl(long)
         * @see UserRecordFailedException
         */
        public TaskCompletionSource <KPLDotNetResult> AddUserRecord(string stream, string partitionKey, string explicitHashKey, MemoryStream data)
        {
            if (stream == null)
            {
                throw new ArgumentException("Stream name cannot be null");
            }

            stream = stream.Trim();

            if (stream.Length == 0)
            {
                throw new ArgumentException("Stream name cannot be empty");
            }

            if (partitionKey == null)
            {
                throw new ArgumentException("partitionKey cannot be null");
            }

            if (partitionKey.Length < 1 || partitionKey.Length > 256)
            {
                throw new ArgumentException("Invalid parition key. Length must be at least 1 and at most 256, got " + partitionKey.Length);
            }

            try
            {
                UTF8Encoding.UTF8.GetBytes(partitionKey);
            }
            catch (Exception e)
            {
                throw new ArgumentException("Partition key must be valid UTF-8");
            }

            BigInteger b = new BigInteger(0);

            if (explicitHashKey != null)
            {
                explicitHashKey = explicitHashKey.Trim();
                try
                {
                    b = new BigInteger(UTF8Encoding.UTF8.GetBytes(explicitHashKey));
                }
                catch (FormatException e)
                {
                    throw new ArgumentException("Invalid explicitHashKey, must be an integer, got " + explicitHashKey);
                }

                if (b != null && b.CompareTo(UINT_128_MAX) > 0 || b.CompareTo(BigInteger.Zero) < 0)
                {
                    throw new ArgumentException("Invalid explicitHashKey, must be greater or equal to zero and less than or equal to (2^128 - 1), got " + explicitHashKey);
                }
            }

            if (data != null && data.Length > 1024 * 1024)
            {
                throw new ArgumentException("Data must be less than or equal to 1MB in size, got " + data.Length + " bytes");
            }

            long id = Interlocked.Increment(ref messageNumber) - 1;
            var  f  = new TaskCompletionSource <KPLDotNetResult>();

            futures.TryAdd(id, f);

            PutRecord pr = new PutRecord()
            {
                StreamName = stream, PartitionKey = partitionKey, Data = data != null?Google.Protobuf.ByteString.CopyFrom(data.ToArray()) : Google.Protobuf.ByteString.Empty
            };

            if (!b.IsZero)
            {
                pr.ExplicitHashKey = b.ToString();
            }

            child.add(new Message()
            {
                Id = (ulong)id, PutRecord = pr
            });

            return(f);
        }
Beispiel #2
0
        public TaskCompletionSource <UserRecordResult> AddUserRecord(string stream, string partitionKey, string explicitHashKey, byte[] data)
        {
            if (string.IsNullOrEmpty(stream))
            {
                throw new ArgumentException("Stream name cannot be null or empty", nameof(stream));
            }

            stream = stream.Trim();
            if (stream.Length == 0)
            {
                throw new ArgumentException("Stream name cannot be empty", nameof(stream));
            }

            if (partitionKey == null)
            {
                throw new ArgumentException("PartitionKey cannot be null", nameof(partitionKey));
            }

            if (partitionKey.Length < 1 || partitionKey.Length > 256)
            {
                throw new ArgumentException($"Invalid parition key. Length must be at least 1 and at most 256, got {partitionKey.Length}", nameof(partitionKey));
            }

            try
            {
                Encoding.UTF8.GetBytes(partitionKey);
            }
            catch (Exception)
            {
                throw new ArgumentException("Partition key must be valid UTF-8", nameof(partitionKey));
            }

            BigInteger?b = null;

            if (explicitHashKey != null)
            {
                explicitHashKey = explicitHashKey.Trim();
                try
                {
                    b = BigInteger.Parse(explicitHashKey);
                }
                catch (FormatException)
                {
                    throw new ArgumentException($"Invalid explicitHashKey, must be an integer, got {explicitHashKey}", nameof(explicitHashKey));
                }

                if (b.Value.CompareTo(UINT_128_MAX) > 0 || b.Value.CompareTo(BigInteger.Zero) < 0)
                {
                    throw new ArgumentException($"Invalid explicitHashKey, must be greater or equal to zero and less than or equal to (2^128 - 1), got {explicitHashKey}", nameof(explicitHashKey));
                }
            }

            if (data != null && data.Length > 1024 * 1024)
            {
                throw new ArgumentException($"Data must be less than or equal to 1MB in size, got {data.Length} bytes", nameof(data));
            }

            long id     = Interlocked.Increment(ref messageNumber) - 1;
            var  future = new FutureOperationResult(new TaskCompletionSource <UserRecordResult>());

            futureOperationResults.TryAdd(id, future);

            var putRecord = new PutRecord
            {
                Data         = data ?? new byte[0],
                StreamName   = stream,
                PartitionKey = partitionKey
            };

            if (b.HasValue)
            {
                putRecord.ExplicitHashKey = b.ToString();
            }

            var msg = new Message
            {
                Id        = (ulong)id,
                PutRecord = putRecord
            };

            child.Add(msg);

            return(future.LeftOrDefault);
        }