public void Enqueue(RedisMessage item, bool highPri) { lock (stdPriority) { if (closed) { throw new InvalidOperationException("The queue is closed"); } if (highPri) { highPriority.Enqueue(item); } else { while (stdPriority.Count >= maxSize) { Monitor.Wait(stdPriority); } stdPriority.Enqueue(item); } if (stdPriority.Count + highPriority.Count == 1) { // wake up any blocked dequeue Monitor.PulseAll(stdPriority); } } }
Task IHashCommands.Set(int db, string key, Dictionary <string, byte[]> values, bool queueJump) { var keyAndFields = new RedisMessage.RedisParameter[(values.Count * 2) + 1]; int index = 0; keyAndFields[index++] = key; foreach (var pair in values) { keyAndFields[index++] = pair.Key; keyAndFields[index++] = pair.Value; } return(ExecuteVoid(RedisMessage.Create(db, RedisLiteral.HMSET, keyAndFields), queueJump)); }
Task <long> ISortedSetCommands.IntersectAndStore(int db, string destination, string[] keys, RedisAggregate aggregate, bool queueJump) { var parameters = new string[keys.Length + 3]; //prepend the number of keys and append the aggregate keyword and the aggregation type parameters[0] = keys.Length.ToString(); keys.CopyTo(parameters, 1); parameters[keys.Length + 1] = "AGGREGATE"; parameters[keys.Length + 2] = aggregate.ToString(); return(ExecuteInt64(RedisMessage.Create(db, RedisLiteral.ZINTERSTORE, destination, parameters), queueJump)); }
void IMessageResult.Complete(RedisResult result, RedisMessage message, bool includeDetail) { if (result.IsCancellation) { RedisConnectionBase.Trace("transaction", "cancelled"); SetInnerReplies(result); completion.TrySetCanceled(); } else if (result.IsError) { RedisConnectionBase.Trace("transaction", "error"); SetInnerReplies(result); completion.SafeSetException(result.Error()); } else { try { if (result.IsNil) { // aborted RedisConnectionBase.Trace("transaction", "aborted"); SetInnerReplies(RedisResult.Cancelled); completion.TrySetResult(false); } else { var items = result.ValueItems; if (items.Length != (queued == null ? 0 : queued.Length)) { throw new InvalidOperationException(string.Format("{0} results expected, {1} received", queued.Length, items.Length)); } RedisConnectionBase.Trace("transaction", "success"); for (int i = 0; i < items.Length; i++) { RedisResult reply = items[i]; RedisConnectionBase.CallbackMode callbackMode; var ctx = parent.ProcessReply(ref reply, queued[i].InnerMessage, out callbackMode); RedisConnectionBase.Trace("transaction", "{0} = {1}", ctx, reply); parent.ProcessCallbacks(ctx, reply, callbackMode); } completion.TrySetResult(true); } } catch (Exception ex) { completion.SafeSetException(ex); throw; } } }
/// <summary> /// Attempts to open the connection to the remote server /// </summary> public async Task Open() { int foundState; if ( (foundState = Interlocked.CompareExchange(ref state, (int)ConnectionState.Opening, (int)ConnectionState.Shiny)) != (int)ConnectionState.Shiny) { throw new InvalidOperationException("Connection is " + (ConnectionState)foundState); // not shiny } try { OnOpening(); socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { NoDelay = true, SendTimeout = ioTimeout }; socket.Connect(host, port); redisStream = new NetworkStream(socket); outBuffer = new BufferedStream(redisStream, 512); // buffer up operations redisStream.ReadTimeout = redisStream.WriteTimeout = ioTimeout; var thread = new Thread(Outgoing) { IsBackground = true, Name = "Redis:outgoing" }; thread.Start(); if (!string.IsNullOrEmpty(password)) { EnqueueMessage(RedisMessage.Create(-1, RedisLiteral.AUTH, password).ExpectOk().Critical(), true); } Task <string> info = GetInfo(); OnInitConnection(); ReadMoreAsync(); var result = await info; ProcessInfo(result); //return ContinueWith(info, ProcessInfo); } catch { Interlocked.CompareExchange(ref state, (int)ConnectionState.Closed, (int)ConnectionState.Opening); throw; } }
// avoid lots of delegate creations internal override sealed IEnumerable <RedisMessage> CreateMessages() { yield return(RedisMessage.Create(db, RedisLiteral.WATCH, key)); IMessageResult msgResult = CreateMessageResult(this); msgResult.Task.ContinueWith(testEquality); RedisMessage message = hashField == null ? RedisMessage.Create(db, RedisLiteral.GET, key) : RedisMessage.Create(db, RedisLiteral.HGET, key, hashField); message.SetMessageResult(msgResult); yield return(message); }
public RedisMessage[] DequeueAll() { lock (stdPriority) { RedisMessage[] result = new RedisMessage[highPriority.Count + stdPriority.Count]; highPriority.CopyTo(result, 0); stdPriority.CopyTo(result, highPriority.Count); highPriority.Clear(); stdPriority.Clear(); // wake up any blocked enqueue Monitor.PulseAll(stdPriority); return result; } }
public RedisMessage[] DequeueAll() { lock (stdPriority) { var result = new RedisMessage[highPriority.Count + stdPriority.Count]; highPriority.CopyTo(result, 0); stdPriority.CopyTo(result, highPriority.Count); highPriority.Clear(); stdPriority.Clear(); // wake up any blocked enqueue Monitor.PulseAll(stdPriority); return(result); } }
internal override void RecordSent(RedisMessage message, bool drainFirst) { base.RecordSent(message, drainFirst); lock (sent) { if (drainFirst && sent.Count != 0) { // drain it down; the dequeuer will wake us Monitor.Wait(sent); } sent.Enqueue(message); } }
protected override void ProcessError(RedisResult result, RedisMessage message, bool includeDetail) { try { var msg = result.Error().Message; if (msg.StartsWith("NOSCRIPT")) { // only way of unloading is to unload all ("SCRIPT FLUSH")... so our // existing cache is now completely toast connection.ResetScriptCache(); } } catch { /* best efforts only */ } base.ProcessError(result, message, includeDetail); }
// avoid lots of delegate creations internal override IEnumerable <RedisMessage> CreateMessages() { yield return(RedisMessage.Create(db, RedisLiteral.WATCH, key)); var msgResult = new MessageResultBoolean(this); msgResult.Task.ContinueWith(testExisted); RedisMessage message = hashField == null ? RedisMessage.Create(db, RedisLiteral.EXISTS, key) : RedisMessage.Create(db, RedisLiteral.HEXISTS, key, hashField); message.SetMessageResult(msgResult); yield return(message); }
internal Task <Dictionary <string, string> > GetConfigImpl(string pattern, bool isInit) { if (string.IsNullOrEmpty(pattern)) { pattern = "*"; } var msg = RedisMessage.Create(-1, RedisLiteral.CONFIG, RedisLiteral.GET, pattern); if (isInit) { msg.DuringInit(); } return(ExecuteStringPairs(msg, false)); }
Task <string> IListCommands.BlockingRemoveLastAndAddFirstString(int db, string source, string destination, int timeoutSeconds, bool queueJump) { var taskSource = new TaskCompletionSource <string>(); var msg = ExecuteRaw(RedisMessage.Create(db, RedisLiteral.BRPOPLPUSH, source, destination, timeoutSeconds), queueJump, taskSource); msg.ContinueWith(x => { var src = (TaskCompletionSource <string>)x.AsyncState; if (x.ShouldSetResult(src)) { src.TrySetResult(x.Result == null || x.Result is MultiRedisResult ? null : x.Result.ValueString); } }); return(taskSource.Task); }
private void ProcessInfo(string done) { try { // process this when available Dictionary <string, string> parsed = ParseInfo(done); string s; Version version; if (parsed.TryGetValue("redis_version", out s) && TryParseVersion(s, out version)) { ServerVersion = version; } if (parsed.TryGetValue("redis_mode", out s) && s == "sentinel") { ServerType = ServerType.Sentinel; } else if (parsed.TryGetValue("role", out s) && s != null) { switch (s) { case "master": ServerType = ServerType.Master; break; case "slave": ServerType = ServerType.Slave; break; } if (!string.IsNullOrEmpty(name)) { RedisFeatures tmp = Features; if (tmp != null && tmp.ClientName) { ExecuteVoid( RedisMessage.Create(-1, RedisLiteral.CLIENT, RedisLiteral.SETNAME, name), true); } } } Interlocked.CompareExchange(ref state, (int)ConnectionState.Open, (int)ConnectionState.Opening); } catch { Close(true); Interlocked.CompareExchange(ref state, (int)ConnectionState.Closed, (int)ConnectionState.Opening); } }
private static RedisMessage CreateSortMessage(int db, string key, string byPattern, string[] getPattern, long offset, long count, bool alpha, bool ascending, string storeKey) { var items = new List <RedisMessage.RedisParameter> { key }; if (!string.IsNullOrEmpty(byPattern)) { items.Add(RedisLiteral.BY); items.Add(byPattern); } if (offset != 0 || (count != -1 && count != long.MaxValue)) { items.Add(RedisLiteral.LIMIT); items.Add(offset); items.Add(count); } if (getPattern != null) { foreach (string pattern in getPattern) { if (!string.IsNullOrEmpty(pattern)) { items.Add(RedisLiteral.GET); items.Add(pattern); } } } if (!ascending) { items.Add(RedisLiteral.DESC); } if (alpha) { items.Add(RedisLiteral.ALPHA); } if (!string.IsNullOrEmpty(storeKey)) { items.Add(RedisLiteral.STORE); items.Add(storeKey); } return(RedisMessage.Create(db, RedisLiteral.SORT, items.ToArray())); }
internal override IEnumerable <RedisMessage> CreateMessages() { yield return(RedisMessage.Create(db, RedisLiteral.WATCH, key)); var msgResult = new MessageResultBoolean(this); // we want this ExecuteSynchronously so that we can exploit the ordered nature of the reader to check all the // results efficiently msgResult.Task.ContinueWith(testExisted, TaskContinuationOptions.ExecuteSynchronously); var message = hashField == null?RedisMessage.Create(db, RedisLiteral.EXISTS, key) : RedisMessage.Create(db, RedisLiteral.HEXISTS, key, hashField); message.SetMessageResult(msgResult); yield return(message); }
private void Outgoing() { try { OnOpened(); int db = 0; RedisMessage next; Trace.WriteLine("Redis send-pump is starting"); bool isHigh, shouldFlush; while (unsent.TryDequeue(false, out next, out isHigh, out shouldFlush)) { if (abort) { CompleteMessage(next, RedisResult.Error("The system aborted before this message was sent")); continue; } if (!next.ChangeState(MessageState.NotSent, MessageState.Sent)) { // already cancelled; not our problem any more... Interlocked.Increment(ref messagesCancelled); continue; } if (isHigh) { Interlocked.Increment(ref queueJumpers); } WriteMessage(ref db, next, null); Flush(shouldFlush); } Interlocked.CompareExchange(ref state, (int)ConnectionState.Closing, (int)ConnectionState.Open); if (redisStream != null) { RedisMessage quit = RedisMessage.Create(-1, RedisLiteral.QUIT).ExpectOk().Critical(); RecordSent(quit, !abort); quit.Write(outBuffer); outBuffer.Flush(); redisStream.Flush(); Interlocked.Increment(ref messagesSent); } Trace.WriteLine("Redis send-pump is exiting"); } catch (Exception ex) { OnError("Outgoing queue", ex, true); } }
internal override object ProcessReply(ref RedisResult result, RedisMessage message) { byte[] expected; if (!result.IsError && (expected = message.Expected) != null) { result = result.IsMatch(expected) ? RedisResult.Pass : RedisResult.Error(result.ValueString); } if (result.IsError && message.MustSucceed) { throw new RedisException("A critical operation failed: " + message); } return(message); }
Task <long> IncrementImpl(int db, string key, long value, bool queueJump) { switch (value) { case 1: return(ExecuteInt64(RedisMessage.Create(db, RedisLiteral.INCR, key), queueJump)); case -1: return(ExecuteInt64(RedisMessage.Create(db, RedisLiteral.DECR, key), queueJump)); } if (value >= 0) { return(ExecuteInt64(RedisMessage.Create(db, RedisLiteral.INCRBY, key, value), queueJump)); } else { return(ExecuteInt64(RedisMessage.Create(db, RedisLiteral.DECRBY, key, -value), queueJump)); } }
Task <KeyValuePair <byte[], double>[]> ISortedSetCommands.Range(int db, string key, double min, double max, bool ascending, bool minInclusive, bool maxInclusive, long offset, long count, bool queueJump) { RedisMessage msg; if (minInclusive && maxInclusive && double.IsNegativeInfinity(min) && double.IsPositiveInfinity(max) && offset >= 0 && count != 0) { // considering entire set; can be done more efficiently with ZRANGE/ZREVRANGE msg = RedisMessage.Create(db, ascending ? RedisLiteral.ZRANGE : RedisLiteral.ZREVRANGE, key, offset, (count < 0 || count == long.MaxValue) ? -1 : (offset + count - 1), RedisLiteral.WITHSCORES); } else if (offset == 0 && (count < 0 || count == long.MaxValue)) { // no need for a LIMIT msg = RedisMessage.Create(db, ascending ? RedisLiteral.ZRANGEBYSCORE : RedisLiteral.ZREVRANGEBYSCORE, key, ascending ? RedisMessage.RedisParameter.Range(min, minInclusive) : RedisMessage.RedisParameter.Range(max, maxInclusive), ascending ? RedisMessage.RedisParameter.Range(max, maxInclusive) : RedisMessage.RedisParameter.Range(min, minInclusive), RedisLiteral.WITHSCORES); } else { msg = RedisMessage.Create(db, ascending ? RedisLiteral.ZRANGEBYSCORE : RedisLiteral.ZREVRANGEBYSCORE, key, ascending ? RedisMessage.RedisParameter.Range(min, minInclusive) : RedisMessage.RedisParameter.Range(max, maxInclusive), ascending ? RedisMessage.RedisParameter.Range(max, maxInclusive) : RedisMessage.RedisParameter.Range(min, minInclusive), RedisLiteral.WITHSCORES, RedisLiteral.LIMIT, offset, (count < 0 || count == long.MaxValue) ? -1 : count); } return(ExecutePairs(msg, queueJump)); }
internal virtual Task Prepare(string[] scripts) { if (scripts == null) { throw new ArgumentNullException(); } var seenHashes = new HashSet <string>(); List <Tuple <string, string> > fetch = new List <Tuple <string, string> >(scripts.Length); for (int i = 0; i < scripts.Length; i++) { string script = scripts[i]; if (!scriptCache.ContainsKey(script)) { string hash = ComputeHash(script); seenHashes.Add(hash); fetch.Add(Tuple.Create(hash, script)); } } if (fetch.Count == 0) { // no point checking, since we'd still be at the mercy of ad-hoc SCRIPT FLUSH timing return(AlwaysTrue); } RedisMessage.RedisParameter[] args = new RedisMessage.RedisParameter[1 + fetch.Count]; args[0] = RedisLiteral.EXISTS; int idx = 1; foreach (var pair in fetch) { args[idx++] = pair.Item1; // hash } TaskCompletionSource <bool> result = new TaskCompletionSource <bool>(); var state = Tuple.Create(result, this, fetch); ExecuteRaw(RedisMessage.Create(-1, RedisLiteral.SCRIPT, args), false, state).ContinueWith(scriptCompletionCallback); return(result.Task); }
internal virtual string GetScriptHash(string script) { var hash = (string)scriptCache[script]; if (hash == null) { // double-checked lock (scriptCache) { hash = (string)scriptCache[script]; if (hash == null) { // compute the hash and ensure it is loaded hash = ComputeHash(script); ExecuteVoid(RedisMessage.Create(-1, RedisLiteral.SCRIPT, RedisLiteral.LOAD, script), queueJump: true); scriptCache[script] = hash; } } } return(hash); }
private Task <long> BitOp(int db, RedisLiteral operation, string destination, string[] keys, bool queueJump) { if (keys == null) { throw new ArgumentNullException("keys"); } if (keys.Length == 0) { throw new ArgumentException("keys"); } var args = new RedisMessage.RedisParameter[keys.Length + 2]; args[0] = operation; args[1] = destination; for (int i = 0; i < keys.Length; i++) { args[i + 2] = keys[i]; } return(ExecuteInt64(RedisMessage.Create(db, RedisLiteral.BITOP, args), queueJump)); }
Task <RedisResult> ReadNext(long cursor, bool running) { if (cursor == 0 && running) { return(null); // end of the line } var pending = new TaskCompletionSource <RedisResult>(); RedisMessage msg; if (key == null) { msg = (string.IsNullOrEmpty(pattern) || pattern == "*") ? RedisMessage.Create(db, command, cursor, RedisLiteral.COUNT, 100) : RedisMessage.Create(db, command, cursor, RedisLiteral.MATCH, pattern, RedisLiteral.COUNT, 100); } else { msg = (string.IsNullOrEmpty(pattern) || pattern == "*") ? RedisMessage.Create(db, command, key, cursor, RedisLiteral.COUNT, 100) : RedisMessage.Create(db, command, key, cursor, RedisLiteral.MATCH, pattern, RedisLiteral.COUNT, 100); } connection.ExecuteRaw(msg, false, pending).ContinueWith(scanContinuation); return(pending.Task); }
Task <ClientInfo[]> IServerCommands.ListClients() { CheckAdmin(); var result = new TaskCompletionSource <ClientInfo[]>(); ExecuteString(RedisMessage.Create(-1, RedisLiteral.CLIENT, RedisLiteral.LIST), false).ContinueWith( task => { if (Condition.ShouldSetResult(task, result)) { try { result.TrySetResult(ClientInfo.Parse(task.Result)); } catch (Exception ex) { result.TrySetException(ex); } } }); return(result.Task); }
Task <object> IScriptingCommands.Eval(int db, string script, string[] keyArgs, object[] valueArgs, bool useCache, bool inferStrings, bool queueJump) { if (string.IsNullOrEmpty(script)) { throw new ArgumentNullException("script"); } var args = new RedisMessage.RedisParameter[ 2 + (keyArgs == null ? 0 : keyArgs.Length) + (valueArgs == null ? 0 : valueArgs.Length)]; args[1] = keyArgs == null ? 0 : keyArgs.Length; int idx = 2; if (keyArgs != null) { for (int i = 0; i < keyArgs.Length; i++) { args[idx++] = keyArgs[i]; } } if (valueArgs != null) { for (int i = 0; i < valueArgs.Length; i++) { args[idx++] = RedisMessage.RedisParameter.Create(valueArgs[i]); } } if (!useCache) { args[0] = script; return(ExecuteScript(RedisMessage.Create(db, RedisLiteral.EVAL, args), inferStrings, queueJump)); } // note this does a SCRIPT LOAD if it is the first time it is seen on this connection args[0] = GetScriptHash(script); return(ExecuteScript(RedisMessage.Create(db, RedisLiteral.EVALSHA, args), inferStrings, queueJump)); }
Task <bool> IStringCommands.TakeLock(int db, string key, string value, int expirySeconds, bool queueJump) { TaskCompletionSource <bool> result = new TaskCompletionSource <bool>(); var features = Features; if (features != null && features.SetConditional) { var raw = ExecuteRaw(RedisMessage.Create(db, RedisLiteral.SET, key, value, RedisLiteral.EX, expirySeconds, RedisLiteral.NX), queueJump, result); raw.ContinueWith(takeLockConditionalContinuation); } else { using (var tran = CreateTransaction()) { tran.AddCondition(Condition.KeyNotExists(db, key)); tran.Strings.Set(db, key, value, expirySeconds); tran.Execute(queueJump, state: result).ContinueWith(takeLockContinuation); } } return(result.Task); }
Task <long> IKeyCommands.GetLength(int db, bool queueJump) { return(ExecuteInt64(RedisMessage.Create(db, RedisLiteral.DBSIZE), queueJump)); }
Task <string> IKeyCommands.Type(int db, string key, bool queueJump) { return(ExecuteString(RedisMessage.Create(db, RedisLiteral.TYPE, key), queueJump)); }
public Task <long> TimeToLive(int db, string key, bool queueJump = false) { return(ExecuteInt64(RedisMessage.Create(db, RedisLiteral.TTL, key), queueJump)); }
public Task <bool> RenameIfNotExists(int db, string fromKey, string toKey, bool queueJump = false) { return(ExecuteBoolean(RedisMessage.Create(db, RedisLiteral.RENAMENX, fromKey, toKey), queueJump)); }
public Task Rename(int db, string fromKey, string toKey, bool queueJump = false) { return(ExecuteVoid(RedisMessage.Create(db, RedisLiteral.RENAME, fromKey, toKey).ExpectOk(), queueJump)); }
internal override object ProcessReply(ref RedisResult result, RedisMessage message) { return null; }
internal override object ProcessReply(ref RedisResult result, RedisMessage message) { byte[] expected; if (!result.IsError && (expected = message.Expected) != null) { result = result.IsMatch(expected) ? RedisResult.Pass : RedisResult.Error(result.ValueString); } if (result.IsError && message.MustSucceed) { throw new RedisException("A critical operation failed: " + message.ToString()); } return message; }
internal Task<object> ExecuteScript(RedisMessage message, bool inferStrings, bool queueJump) { var msgResult = new MessageResultScript(this, inferStrings); message.SetMessageResult(msgResult); EnqueueMessage(message, queueJump); return msgResult.Task; }
public MultiMessage(RedisConnection parent, RedisMessage[] messages) : base(-1, RedisLiteral.MULTI) { exec = new ExecMessage(parent); this.messages = messages; ExpectOk(); }
void IMessageResult.Complete(RedisResult result, RedisMessage message, bool includeDetail) { if (result.IsCancellation) { RedisConnectionBase.Trace("transaction", "cancelled"); SetInnerReplies(result); completion.TrySetCanceled(); } else if (result.IsError) { RedisConnectionBase.Trace("transaction", "error"); SetInnerReplies(result); completion.SafeSetException(result.Error()); } else { try { if (result.IsNil) { // aborted RedisConnectionBase.Trace("transaction", "aborted"); SetInnerReplies(RedisResult.Cancelled); completion.TrySetResult(false); } else { var items = result.ValueItems; if (items.Length != (queued == null ? 0 : queued.Length)) throw new InvalidOperationException(string.Format("{0} results expected, {1} received", queued.Length, items.Length)); RedisConnectionBase.Trace("transaction", "success"); for (int i = 0; i < items.Length; i++) { RedisResult reply = items[i]; RedisConnectionBase.CallbackMode callbackMode; var ctx = parent.ProcessReply(ref reply, queued[i].InnerMessage, out callbackMode); RedisConnectionBase.Trace("transaction", "{0} = {1}", ctx, reply); parent.ProcessCallbacks(ctx, reply, callbackMode); } completion.TrySetResult(true); } } catch (Exception ex) { completion.SafeSetException(ex); throw; } } }
public MultiMessage(RedisConnection parent, RedisMessage[] messages, List<Condition> conditions, object state) : base(-1, RedisLiteral.MULTI) { exec = new ExecMessage(parent, state); this.conditions = conditions; this.messages = messages; ExpectOk().Critical(); }
public QueuedMessage(RedisMessage innnerMessage) : base(innnerMessage.Db, innnerMessage.Command) { if (innnerMessage == null) throw new ArgumentNullException("innnerMessage"); this.innnerMessage = innnerMessage; Expect(RedisLiteral.QUEUED).Critical(); }
public void Abort(RedisMessage[] messages) { if (messages != null) { for (int i = 0; i < messages.Length; i++) { var reply = RedisResult.Cancelled; RedisConnectionBase.CallbackMode callbackMode; var ctx = parent.ProcessReply(ref reply, messages[i], out callbackMode); RedisConnectionBase.Trace("transaction", "{0} = {1}", ctx, reply); parent.ProcessCallbacks(ctx, reply, callbackMode); } } }
public bool TryDequeue(bool noWait, out RedisMessage value, out bool isHigh, out bool shouldFlush) { lock (stdPriority) { int timeoutMilliseconds = this.keepAliveMilliseconds; while (highPriority.Count == 0 && stdPriority.Count == 0 && timeoutMilliseconds > 0) { if (closed || noWait) { value = null; isHigh = false; shouldFlush = true; return false; } if (timeoutMilliseconds == int.MaxValue) { Monitor.Wait(stdPriority); } else { var watch = Stopwatch.StartNew(); Monitor.Wait(stdPriority, timeoutMilliseconds); watch.Stop(); timeoutMilliseconds -= (int) watch.ElapsedMilliseconds; } } int loCount = stdPriority.Count, hiCount = highPriority.Count; isHigh = hiCount > 0; if (isHigh) { value = highPriority.Dequeue(); hiCount--; shouldFlush = hiCount == 0; } else if(loCount > 0) { value = stdPriority.Dequeue(); loCount--; shouldFlush = loCount == 0; } else { // nothing there! it must have been a KeepAlive timeout then shouldFlush = true; // want this sent NOW value = new PingMessage(); } if ((!isHigh && loCount == maxSize - 1) || (loCount == 0 && hiCount == 0)) { // wake up any blocked enqueue Monitor.PulseAll(stdPriority); } if (isHigh && loCount == 0) isHigh = false;//can't be high if it didn't overtake return true; } }
internal override void RecordSent(RedisMessage message, bool drainFirst) { base.RecordSent(message, drainFirst); lock (sent) { if (drainFirst && sent.Count != 0) { // drain it down; the dequeuer will wake us Monitor.Wait(sent); } sent.Enqueue(message); } }
public BatchMessage(RedisMessage[] messages) : base(-1, RedisLiteral.PING) { if (messages == null) throw new ArgumentNullException("messages"); this.messages = messages; }