/// <summary>
        /// Delete an object stored in the deduplication index.
        /// This method will use the callbacks supplied in the method signature.
        /// </summary>
        /// <param name="key">The object key.</param>
        /// <param name="callbacks">CallbackMethods object containing callback methods.</param>
        public void Delete(string key, DedupeCallbacks callbacks)
        {
            if (String.IsNullOrEmpty(key))
            {
                throw new ArgumentNullException(nameof(key));
            }
            if (callbacks == null)
            {
                throw new ArgumentNullException(nameof(callbacks));
            }
            if (callbacks.DeleteChunk == null)
            {
                throw new ArgumentException("DeleteChunk callback must be specified.");
            }
            key = DedupeCommon.SanitizeString(key);

            List <string> garbageCollectChunks = _Database.Delete(key);

            if (garbageCollectChunks != null && garbageCollectChunks.Count > 0)
            {
                foreach (string gcKey in garbageCollectChunks)
                {
                    callbacks.DeleteChunk(gcKey);
                }
            }
        }
        /// <summary>
        /// Write an object to the deduplication index.
        /// This method will use the callbacks supplied in the method signature.
        /// </summary>
        /// <param name="key">The object key.  Must be unique in the index.</param>
        /// <param name="callbacks">CallbackMethods object containing callback methods.</param>
        /// <param name="contentLength">The length of the data.</param>
        /// <param name="stream">The stream containing the data.</param>
        public void Write(string key, DedupeCallbacks callbacks, long contentLength, Stream stream)
        {
            #region Initialize

            if (String.IsNullOrEmpty(key))
            {
                throw new ArgumentNullException(nameof(key));
            }
            if (_Database.Exists(key))
            {
                throw new ArgumentException("An object with key '" + key + "' already exists.");
            }
            if (callbacks == null)
            {
                throw new ArgumentNullException(nameof(callbacks));
            }
            if (callbacks.WriteChunk == null)
            {
                throw new ArgumentException("WriteChunk callback must be specified.");
            }
            if (callbacks.DeleteChunk == null)
            {
                throw new ArgumentException("DeleteChunk callback must be specified.");
            }
            if (contentLength < 1)
            {
                throw new ArgumentException("Content length must be at least one byte.");
            }
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }
            if (!stream.CanRead)
            {
                throw new InvalidOperationException("Cannot read from the supplied stream.");
            }
            key = DedupeCommon.SanitizeString(key);

            bool garbageCollectionRequired = false;

            #endregion

            #region Chunk-Data

            List <DedupeChunk> chunks = new List <DedupeChunk>();

            try
            {
                Action <DedupeChunk, DedupeObjectMap> processChunk = delegate(DedupeChunk chunk, DedupeObjectMap map)
                {
                    if (chunk == null || map == null)
                    {
                        return;
                    }

                    _Database.IncrementChunkRefcount(chunk.Key, chunk.Length);
                    _Database.AddObjectMap(key, chunk.Key, chunk.Length, map.ChunkPosition, map.ChunkAddress);
                    callbacks.WriteChunk(chunk);
                };

                chunks = ChunkStream(key, contentLength, stream, processChunk);

                _Database.AddObject(key, contentLength);
            }
            finally
            {
                if (garbageCollectionRequired)
                {
                    List <string> garbageCollectKeys = _Database.Delete(key);
                    if (garbageCollectKeys != null && garbageCollectKeys.Count > 0)
                    {
                        foreach (string gcKey in garbageCollectKeys)
                        {
                            callbacks.DeleteChunk(gcKey);
                        }
                    }
                }
            }

            #endregion
        }