/// <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 }