public void Dispose() { _rds.ReceiveTimeout = _oldReceiveTimeout; _runing = false; _rds.ReleaseSocket(); ClearAndTrySetExpcetion(null); }
internal void Cancel(params Guid[] ids) { if (ids == null) { return; } var readyUnsubInterKeys = new List <string>(); foreach (var id in ids) { if (_cancels.TryRemove(id, out var oldkeys)) { foreach (var oldkey in oldkeys) { if (_registers.TryGetValue(oldkey, out var oldrecvs) && oldrecvs.TryRemove(id, out var oldrecv) && oldrecvs.Any() == false) { readyUnsubInterKeys.Add(oldkey); } } } } var unsub = readyUnsubInterKeys.Where(a => !a.StartsWith(_psub_regkey_prefix)).ToArray(); var punsub = readyUnsubInterKeys.Where(a => a.StartsWith(_psub_regkey_prefix)).Select(a => a.Replace(_psub_regkey_prefix, "")).ToArray(); if (unsub.Any()) { Call("UNSUBSCRIBE".Input(unsub)); } if (punsub.Any()) { Call("PUNSUBSCRIBE".Input(punsub)); } if (!_cancels.Any()) { lock (_lock) if (!_cancels.Any()) { _redisSocket.ReleaseSocket(); } } }
public override TValue AdapterCall <TValue>(CommandPacket cmd, Func <RedisResult, TValue> parse) { return(TopOwner.LogCall(cmd, () => { _redisSocket.Write(cmd); var rt = _redisSocket.Read(cmd); if (cmd._command == "QUIT") { _redisSocket.ReleaseSocket(); } return parse(rt); })); }
public override TValue AdapterCall <TValue>(CommandPacket cmd, Func <RedisResult, TValue> parse) { return(TopOwner.LogCall(cmd, () => { _redisSocket.Write(cmd); var rt = _redisSocket.Read(cmd._flagReadbytes); if (cmd._command == "QUIT") { _redisSocket.ReleaseSocket(); } rt.IsErrorThrow = TopOwner._isThrowRedisSimpleError; return parse(rt); })); }
WriteAsyncInfo WriteInQueue(CommandPacket cmd) { var ret = new WriteAsyncInfo { Command = cmd }; if (_rds.ClientReply == ClientReplyType.on) { ret.TaskCompletionSource = new TaskCompletionSource <RedisResult>(); } var isnew = false; lock (_writeAsyncLock) { _writeQueue.Enqueue(ret); if (_isfirst == false) { isnew = _isfirst = true; } if (_bufferStream == null) { _bufferStream = new MemoryStream(); } new RespHelper.Resp3Writer(_bufferStream, _rds.Encoding, _rds.Protocol).WriteCommand(cmd); } if (isnew) { //Thread.CurrentThread.Join(TimeSpan.FromTicks(1000)); try { if (_rds.IsConnected == false) { _rds.Connect(); } } catch (Exception ioex) { lock (_writeAsyncLock) { while (_writeQueue.TryDequeue(out var wq)) { wq.TaskCompletionSource?.TrySetException(ioex); } _bufferStream.Close(); _bufferStream.Dispose(); _bufferStream = null; } _rds.ReleaseSocket(); _end(_rds, ioex); throw ioex; } for (var a = 0; a < 100; a++) { var cou = _writeQueue.Count; if (cou > 100) { break; } } var localQueue = new Queue <WriteAsyncInfo>(); long localQueueThrowException(Exception exception) { long counter = 0; while (localQueue.Any()) { var witem = localQueue.Dequeue(); if (exception != null) { witem.TaskCompletionSource?.TrySetException(exception); } else { witem.TaskCompletionSource?.TrySetCanceled(); } counter = Interlocked.Decrement(ref _writeCounter); } return(counter); } var iswait = _writeCounter > 1; if (iswait) { Thread.CurrentThread.Join(10); } _begin(); while (true) { if (_writeQueue.Any() == false) { Thread.CurrentThread.Join(10); continue; } lock (_writeAsyncLock) { while (_writeQueue.TryDequeue(out var wq)) { localQueue.Enqueue(wq); } _bufferStream.Position = 0; try { _bufferStream.CopyTo(_rds.Stream); _bufferStream.Close(); _bufferStream.Dispose(); _bufferStream = null; } catch (Exception ioex) { localQueueThrowException(ioex); _bufferStream.Close(); _bufferStream.Dispose(); _bufferStream = null; _rds.ReleaseSocket(); _end(_rds, ioex); throw ioex; } } long counter = 0; RedisResult rt = null; //sb.AppendLine($"{name} 线程{Thread.CurrentThread.ManagedThreadId}:合并读取 {localQueue.Count} 个命令 total:{sw.ElapsedMilliseconds} ms"); while (localQueue.Any()) { var witem = localQueue.Dequeue(); try { rt = _rds.Read(false); } catch (Exception ioex) { localQueueThrowException(ioex); _rds.ReleaseSocket(); _end(_rds, ioex); throw ioex; } witem.TaskCompletionSource.TrySetResult(rt); counter = Interlocked.Decrement(ref _writeCounter); } if (counter == 0 && _finish()) { break; } Thread.CurrentThread.Join(1); //sb.AppendLine($"{name} 线程{Thread.CurrentThread.ManagedThreadId}:等待 1ms + {_writeQueue.Count} total:{sw.ElapsedMilliseconds} ms"); } //sb.AppendLine($"{name} 线程{Thread.CurrentThread.ManagedThreadId}:退出 total:{sw.ElapsedMilliseconds} ms"); _end(_rds, null); } return(ret); }
internal IDisposable Subscribe(bool psub, string[] channels, Action <string, string, object> handler) { if (_stoped) { return(new PubSubSubscribeDisposable(this, null)); } channels = channels?.Distinct().Where(a => !string.IsNullOrEmpty(a)).ToArray(); //In case of external modification if (channels?.Any() != true) { return(new PubSubSubscribeDisposable(this, null)); } var id = Guid.NewGuid(); var time = DateTime.Now; var regkeys = channels.Select(a => psub ? $"{_psub_regkey_prefix}{a}" : a).ToArray(); for (var a = 0; a < regkeys.Length; a++) { ConcurrentDictionary <Guid, RegisterInfo> dict = null; lock (_lock) dict = _registers.GetOrAdd(regkeys[a], k1 => new ConcurrentDictionary <Guid, RegisterInfo>()); dict.TryAdd(id, new RegisterInfo(id, handler, time)); } lock (_lock) _cancels.TryAdd(id, regkeys); var isnew = false; if (IsSubscribed == false) { lock (_lock) { if (IsSubscribed == false) { _redisSocket = _topOwner.Adapter.GetRedisSocket(null); IsSubscribed = isnew = true; } } } if (isnew) { new Thread(() => { _redisSocketReceiveTimeoutOld = _redisSocket.ReceiveTimeout; _redisSocket.ReceiveTimeout = TimeSpan.Zero; var timer = new Timer(state => { _topOwner.Adapter.Refersh(_redisSocket); //防止 IdleBus 超时回收 try { _redisSocket.Write("PING"); } catch { } }, null, 10000, 10000); var readCmd = "PubSubRead".SubCommand(null).FlagReadbytes(false); while (_stoped == false) { RedisResult rt = null; try { rt = _redisSocket.Read(readCmd); } catch { Thread.CurrentThread.Join(100); if (_cancels.Any()) { continue; } break; } var val = rt.Value as object[]; if (val == null) { continue; //special case } var val1 = val[0].ConvertTo <string>(); switch (val1) { case "pong": case "punsubscribe": case "unsubscribe": continue; case "pmessage": OnData(val[1].ConvertTo <string>(), val[2].ConvertTo <string>(), val[3]); continue; case "message": OnData(null, val[1].ConvertTo <string>(), val[2]); continue; } } timer.Dispose(); lock (_lock) { IsSubscribed = false; _redisSocket.ReceiveTimeout = _redisSocketReceiveTimeoutOld; _redisSocket.ReleaseSocket(); _redisSocket.Dispose(); _redisSocket = null; } }).Start(); } Call((psub ? "PSUBSCRIBE" : "SUBSCRIBE").Input(channels)); return(new PubSubSubscribeDisposable(this, () => Cancel(id))); }