/// <summary> /// Removes the serialized objects at the given cache keys from the cache. /// </summary> /// <param name="cacheKeys">The cache keys.</param> public void Remove(IEnumerable<string> cacheKeys) { // Sanitize if (cacheKeys == null) { throw new ArgumentNullException("cacheKeys"); } if (!cacheKeys.Any()) { throw new ArgumentException("must have at least one element", "cacheKeys"); } byte[] command = null; using (var memoryStream = new MemoryStream()) { memoryStream.WriteControlBytePlaceHolder(); memoryStream.Write("del"); foreach (var cacheKey in cacheKeys) { memoryStream.WriteSpace(); memoryStream.Write(cacheKey); } command = memoryStream.ToArray(); } // Set control byte command.SetControlByte(DacheProtocolHelper.MessageType.RepeatingCacheKeys); // Send _client.Send(command); }
/// <summary> /// Removes all serialized objects associated with the given tag names and optionally with keys matching the given pattern. /// WARNING: THIS IS A VERY EXPENSIVE OPERATION FOR LARGE TAG CACHES. USE WITH CAUTION. /// </summary> /// <param name="tagNames">The tag names.</param> /// <param name="pattern">The search pattern (RegEx). Optional. If not specified, the default of "*" is used to indicate match all.</param> public void RemoveTagged(IEnumerable<string> tagNames, string pattern = "*") { // Sanitize if (tagNames == null) { throw new ArgumentNullException("tagNames"); } if (!tagNames.Any()) { throw new ArgumentException("must have at least one element", "tagNames"); } if (string.IsNullOrWhiteSpace(pattern)) { throw new ArgumentException("cannot be null, empty, or white space", "pattern"); } byte[] command; using (var memoryStream = new MemoryStream()) { memoryStream.WriteControlBytePlaceHolder(); memoryStream.Write("del-tag"); memoryStream.WriteSpace(); memoryStream.Write(pattern); foreach (var tagName in tagNames) { memoryStream.WriteSpace(); memoryStream.Write(tagName); } command = memoryStream.ToArray(); } // Set control byte command.SetControlByte(DacheProtocolHelper.MessageType.RepeatingCacheKeys); // Send _client.Send(command); }
/// <summary> /// Gets all serialized objects associated with the given tag name. /// </summary> /// <param name="tagNames">The tag names.</param> /// <returns>A list of the serialized objects.</returns> public List<byte[]> GetTagged(IEnumerable<string> tagNames) { // Sanitize if (tagNames == null) { throw new ArgumentNullException("tagNames"); } if (!tagNames.Any()) { throw new ArgumentException("must have at least one element", "tagNames"); } byte[] command = null; using (var memoryStream = new MemoryStream()) { memoryStream.WriteControlBytePlaceHolder(); memoryStream.Write("get-tag"); foreach (var tagName in tagNames) { memoryStream.WriteSpace(); memoryStream.Write(tagName); } command = memoryStream.ToArray(); } // Set control byte command.SetControlByte(DacheProtocolHelper.MessageType.RepeatingCacheKeys); // Send and receive command = _client.SendReceive(command); // Parse string var commandResult = DacheProtocolHelper.CommunicationEncoding.GetString(command); // Verify that we got something if (commandResult == null) { return null; } // Parse command from bytes var commandResultParts = commandResult.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); return ParseCacheObjects(commandResultParts); }
/// <summary> /// Gets all cache keys associated with the given tag names and optionally matching the given pattern. /// WARNING: THIS IS A VERY EXPENSIVE OPERATION FOR LARGE TAG CACHES. USE WITH CAUTION. /// </summary> /// <param name="tagNames">The tag names.</param> /// <param name="pattern">The search pattern (RegEx). Optional. If not specified, the default of "*" is used to indicate match all.</param> /// <returns>The list of cache keys matching the provided pattern.</returns> public List<byte[]> GetCacheKeysTagged(IEnumerable<string> tagNames, string pattern = "*") { if (tagNames == null) { throw new ArgumentNullException("tagNames"); } if (!tagNames.Any()) { throw new ArgumentException("must have at least one element", "tagNames"); } if (string.IsNullOrWhiteSpace(pattern)) { throw new ArgumentException("cannot be null, empty, or white space", "pattern"); } byte[] command; using (var memoryStream = new MemoryStream()) { memoryStream.WriteControlBytePlaceHolder(); memoryStream.Write("keys-tag"); memoryStream.WriteSpace(); memoryStream.Write(pattern); foreach (var tagName in tagNames) { memoryStream.WriteSpace(); memoryStream.Write(tagName); } command = memoryStream.ToArray(); } // Set control byte command.SetControlByte(DacheProtocolHelper.MessageType.Literal); // Send and receive var rawResult = _client.SendReceive(command); // Verify that we got something if (rawResult == null) { return null; } // Parse string var decodedResult = DacheProtocolHelper.CommunicationEncoding.GetString(rawResult); if (string.IsNullOrWhiteSpace(decodedResult)) { return null; } // Parse command from bytes var commandResultParts = decodedResult.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); return ParseCacheObjects(commandResultParts); }
/// <summary> /// Adds or updates the interned serialized objects in the cache at the given cache keys. /// NOTE: interned objects use significantly less memory when placed in the cache multiple times however cannot expire or be evicted. /// You must remove them manually when appropriate or else you may face a memory leak. /// </summary> /// <param name="cacheKeysAndSerializedObjects">The cache keys and associated serialized objects.</param> /// <param name="tagName">The tag name.</param> public void AddOrUpdateTaggedInterned(IEnumerable<KeyValuePair<string, byte[]>> cacheKeysAndSerializedObjects, string tagName) { // Sanitize if (cacheKeysAndSerializedObjects == null) { throw new ArgumentNullException("cacheKeysAndSerializedObjects"); } if (!cacheKeysAndSerializedObjects.Any()) { throw new ArgumentException("must have at least one element", "cacheKeysAndSerializedObjects"); } if (string.IsNullOrWhiteSpace(tagName)) { throw new ArgumentException("cannot be null, empty, or white space", "tagName"); } byte[] command = null; using (var memoryStream = new MemoryStream()) { memoryStream.WriteControlBytePlaceHolder(); memoryStream.Write("set-tag-intern {0}", tagName); foreach (var cacheKeyAndSerializedObjectKvp in cacheKeysAndSerializedObjects) { memoryStream.WriteSpace(); memoryStream.Write(cacheKeyAndSerializedObjectKvp.Key); memoryStream.WriteSpace(); memoryStream.WriteBase64(cacheKeyAndSerializedObjectKvp.Value); } command = memoryStream.ToArray(); } // Set control byte command.SetControlByte(DacheProtocolHelper.MessageType.RepeatingCacheKeysAndObjects); // Send _client.Send(command); }
/// <summary> /// Adds or updates the serialized objects in the cache at the given cache keys. /// </summary> /// <param name="cacheKeysAndSerializedObjects">The cache keys and associated serialized objects.</param> /// <param name="slidingExpiration">The sliding expiration.</param> public void AddOrUpdate(IEnumerable<KeyValuePair<string, byte[]>> cacheKeysAndSerializedObjects, TimeSpan slidingExpiration) { // Sanitize if (cacheKeysAndSerializedObjects == null) { throw new ArgumentNullException("cacheKeysAndSerializedObjects"); } if (!cacheKeysAndSerializedObjects.Any()) { throw new ArgumentException("must have at least one element", "cacheKeysAndSerializedObjects"); } byte[] command = null; using (var memoryStream = new MemoryStream()) { memoryStream.WriteControlBytePlaceHolder(); memoryStream.Write("set {0}", (int)slidingExpiration.TotalSeconds); foreach (var cacheKeyAndSerializedObjectKvp in cacheKeysAndSerializedObjects) { memoryStream.WriteSpace(); memoryStream.Write(cacheKeyAndSerializedObjectKvp.Key); memoryStream.WriteSpace(); memoryStream.WriteBase64(cacheKeyAndSerializedObjectKvp.Value); } command = memoryStream.ToArray(); } // Set control byte command.SetControlByte(DacheProtocolHelper.MessageType.RepeatingCacheKeysAndObjects); // Send _client.Send(command); }
private byte[] ProcessCommand(string command, DacheProtocolHelper.MessageType messageType) { // Sanitize if (command == null) { return null; } if (string.IsNullOrWhiteSpace(command)) { return null; } string[] commandParts = command.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (commandParts.Length == 0) { return null; } List<byte[]> results; byte[] commandResult = null; switch (messageType) { case DacheProtocolHelper.MessageType.Literal: { if (string.Equals(commandParts[0], "keys", StringComparison.OrdinalIgnoreCase)) { // Sanitize the command if (commandParts.Length != 2) { return null; } var pattern = commandParts[1]; results = GetCacheKeys(pattern); // Structure the results for sending using (var memoryStream = new MemoryStream()) { for (int i = 0; i < results.Count; i++) { if (i != 0) { memoryStream.WriteSpace(); } memoryStream.WriteBase64(results[i]); } commandResult = memoryStream.ToArray(); } } else if (string.Equals(commandParts[0], "clear", StringComparison.OrdinalIgnoreCase)) { Clear(); } break; } case DacheProtocolHelper.MessageType.RepeatingCacheKeys: { // Determine command if (string.Equals(commandParts[0], "get", StringComparison.OrdinalIgnoreCase)) { // Sanitize the command if (commandParts.Length < 2) { return null; } var cacheKeys = commandParts.Skip(1); results = Get(cacheKeys); // Structure the results for sending using (var memoryStream = new MemoryStream()) { for (int i = 0; i < results.Count; i++) { if (i != 0) { memoryStream.WriteSpace(); } memoryStream.WriteBase64(results[i]); } commandResult = memoryStream.ToArray(); } } if (string.Equals(commandParts[0], "get-tag", StringComparison.OrdinalIgnoreCase)) { // Sanitize the command if (commandParts.Length < 2) { return null; } var tagNames = commandParts.Skip(1); results = GetTagged(tagNames); // Structure the results for sending using (var memoryStream = new MemoryStream()) { for (int i = 0; i < results.Count; i++) { if (i != 0) { memoryStream.WriteSpace(); } memoryStream.WriteBase64(results[i]); } commandResult = memoryStream.ToArray(); } } else if (string.Equals(commandParts[0], "del-tag", StringComparison.OrdinalIgnoreCase)) { // sample commands: // del-tag * tagName1 // del-tag * tagName1 tagName2 // del-tag myPrefix* tagName1 tagName2 // Sanitize the command if (commandParts.Length < 3) { return null; } var pattern = commandParts[1]; var tagNames = commandParts.Skip(2); RemoveTagged(tagNames, pattern); } else if (string.Equals(commandParts[0], "del", StringComparison.OrdinalIgnoreCase)) { // Sanitize the command if (commandParts.Length < 2) { return null; } var cacheKeys = commandParts.Skip(1); Remove(cacheKeys); } else if (string.Equals(commandParts[0], "keys-tag", StringComparison.OrdinalIgnoreCase)) { // Sanitize the command if (commandParts.Length < 3) { return null; } var pattern = commandParts[1]; var tagNames = commandParts.Skip(2); results = GetCacheKeysTagged(tagNames, pattern); // Structure the results for sending using (var memoryStream = new MemoryStream()) { for (int i = 0; i < results.Count; i++) { if (i != 0) { memoryStream.WriteSpace(); } memoryStream.WriteBase64(results[i]); } commandResult = memoryStream.ToArray(); } } break; } case DacheProtocolHelper.MessageType.RepeatingCacheKeysAndObjects: { // Determine command IEnumerable<KeyValuePair<string, byte[]>> cacheKeysAndObjects; if (string.Equals(commandParts[0], "set-tag-intern", StringComparison.OrdinalIgnoreCase)) { // Only one method, so call it if (commandParts.Length == 2) { cacheKeysAndObjects = ParseCacheKeysAndObjects(commandParts, 2); AddOrUpdateTaggedInterned(cacheKeysAndObjects, commandParts[1]); } } else if (string.Equals(commandParts[0], "set-intern", StringComparison.OrdinalIgnoreCase)) { // Only one method, so call it cacheKeysAndObjects = ParseCacheKeysAndObjects(commandParts, 1); AddOrUpdateInterned(cacheKeysAndObjects); } else if (string.Equals(commandParts[0], "set-tag", StringComparison.OrdinalIgnoreCase)) { // set-tag command should have no less than 4 parts: set-tag tagName keyName keyValue if (commandParts.Length < 4) { return null; } // Check whether we have absolute or sliding options if (commandParts.Length % 2 == 0) { // Regular set cacheKeysAndObjects = ParseCacheKeysAndObjects(commandParts, 2); AddOrUpdateTagged(cacheKeysAndObjects, commandParts[1]); } else { // Get absolute or sliding expiration int slidingExpiration; DateTimeOffset absoluteExpiration; if (int.TryParse(commandParts[2], out slidingExpiration)) { // Sliding expiration cacheKeysAndObjects = ParseCacheKeysAndObjects(commandParts, 3); AddOrUpdateTagged(cacheKeysAndObjects, commandParts[1], TimeSpan.FromSeconds(slidingExpiration)); } else if (DateTimeOffset.TryParseExact(commandParts[2], DacheProtocolHelper.AbsoluteExpirationFormat, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out absoluteExpiration)) { // Absolute expiration cacheKeysAndObjects = ParseCacheKeysAndObjects(commandParts, 3); AddOrUpdateTagged(cacheKeysAndObjects, commandParts[1], absoluteExpiration); } } } else if (string.Equals(commandParts[0], "set", StringComparison.OrdinalIgnoreCase)) { // Check whether we have absolute or sliding options if (commandParts.Length % 2 == 1) { // Regular set cacheKeysAndObjects = ParseCacheKeysAndObjects(commandParts, 1); AddOrUpdate(cacheKeysAndObjects); } else { // Get absolute or sliding expiration int slidingExpiration; DateTimeOffset absoluteExpiration; if (int.TryParse(commandParts[1], out slidingExpiration)) { // sliding expiration cacheKeysAndObjects = ParseCacheKeysAndObjects(commandParts, 2); AddOrUpdate(cacheKeysAndObjects, TimeSpan.FromSeconds(slidingExpiration)); } else if (DateTimeOffset.TryParseExact(commandParts[1], DacheProtocolHelper.AbsoluteExpirationFormat, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out absoluteExpiration)) { // absolute expiration cacheKeysAndObjects = ParseCacheKeysAndObjects(commandParts, 2); AddOrUpdate(cacheKeysAndObjects, absoluteExpiration); } } } break; } } // Return the result - may be null if there was no valid message return commandResult; }