private void WriteInt96(BinaryWriter writer, SchemaElement schema, IList data) { if (schema.ElementType == typeof(DateTimeOffset)) { foreach (DateTimeOffset dto in data) { var nano = new NanoTime(dto); nano.Write(writer); } } else if (schema.ElementType == typeof(DateTime)) { foreach (DateTime dtm in data) { var nano = new NanoTime(dtm.ToUniversalTime()); nano.Write(writer); } } else { foreach (byte[] dto in data) { writer.Write(dto); } } }
private void WorkLoop() { var test = Interlocked.CompareExchange(ref workerState, -1, -1); //if (Interlocked.CompareExchange(ref workerState, -1, -1) != WORKER_INIT) if (test == WORKER_KILLED) { throw new InvalidOperationException($"This should not happen! {test}"); } while (Interlocked.CompareExchange(ref workerState, 0, 0) != WORKER_KILLED) { ExpireTimeouts(); long newDeadline = CalcNewDeadline(); var sleepTime = newDeadline - time.Elapsed; // tick before sleep so that timeout added while sleeping // will be delayed by a tick to avoid early wake up. Sleep(NanoTime.ToMilliseconds(sleepTime)); Interlocked.Increment(ref ticked); } unprocessedTimeouts = new HashSet <TimedCallback>(); foreach (var slot in slots) { TimedCallback timeout = null; while ((timeout = slot.TryPop()) != null) { unprocessedTimeouts.Add(timeout); } } stopBarier.Signal(); }
public void TestExecutionOnTime() { var tickDuration = TimeSpan.FromMilliseconds(200); var timeout = TimeSpan.FromMilliseconds(125); var nanoTimeout = NanoTime.FromMilliseconds(125); var maxTimeout = 2 * (tickDuration + timeout); var nanoMaxTimeout = NanoTime.FromMilliseconds(maxTimeout.TotalMilliseconds); HashedWheelTimer timer = new HashedWheelTimer(tickDuration); var queue = new BlockingCollection <long>(); var watch = new ConcurrentStopwatch(); watch.Start(); int scheduledTasks = 100000; for (int i = 0; i < scheduledTasks; i++) { var start = watch.Elapsed; timer.ScheduleTimeout(() => { queue.Add(watch.Elapsed - start); }, timeout); } for (int i = 0; i < scheduledTasks; i++) { long delay = queue.Take(); Assert.True(delay >= nanoTimeout && delay < nanoMaxTimeout, i + ": Timeout + " + scheduledTasks + " delay " + delay + " must be " + timeout + " < " + maxTimeout); } timer.Stop(); }
private void WriteAsInt96(BinaryWriter writer, IList values) { foreach (DateTimeOffset dto in values) { var nano = new NanoTime(dto); nano.Write(writer); } }
private void ReadAsInt96(BinaryReader reader, IList result) { while (reader.BaseStream.Position + 12 <= reader.BaseStream.Length) { var nano = new NanoTime(reader.ReadBytes(12), 0); DateTimeOffset dt = nano; result.Add(dt.UtcDateTime); } }
public void ConvertToDateTimeOffset_PreservesTicks() { var dto = new DateTimeOffset(2021, 05, 14, 17, 52, 31, TimeSpan.Zero); dto = dto.Add(TimeSpan.FromTicks(1234567)); var nanoTime = new NanoTime(dto); var convertedDto = (DateTimeOffset)nanoTime; Assert.Equal(dto, convertedDto); }
private void DefaultInitialize() { DefaultTimeout = NanoTime.FromSeconds(10); TicksInterval = NanoTime.FromMilliseconds(50); InitializeSlots(); workerThread = new Thread(WorkLoop); time.Start(); workerThread.Start(); ticked = 0; }
/// <summary> /// Create a timer with custamizable ticks interval and default timeout of TimedCallback. /// </summary> /// <param name="interval"></param> /// <param name="defaultTimeout"></param> /// <param name="policy"></param> public HashedWheelTimer(TimeSpan interval, TimeSpan defaultTimeout, SleepPolicy policy = SleepPolicy.Default) { TicksInterval = NanoTime.FromMilliseconds(interval.TotalMilliseconds); DefaultTimeout = NanoTime.FromMilliseconds(defaultTimeout.TotalMilliseconds); ticked = 0; SetSleep(policy); InitializeSlots(); workerThread = new Thread(WorkLoop); time.Start(); workerThread.Start(); }
private int ReadAsInt96(BinaryReader reader, DateTimeOffset[] dest, int offset) { int idx = offset; while (reader.BaseStream.Position + 12 <= reader.BaseStream.Length) { var nano = new NanoTime(reader.ReadBytes(12), 0); DateTimeOffset dt = nano; dest[idx++] = dt; } return(idx - offset); }
public void TestDelayTimeoutShouldNotLargerThanSingleTickDuration(int tickInterval, int timeout) { var watch = new ConcurrentStopwatch(); var barrier = new CountdownEvent(1); var timer = new HashedWheelTimer(interval: TimeSpan.FromMilliseconds(tickInterval)); long elapsed = 0; watch.Start(); timer.ScheduleTimeout(() => { Interlocked.Exchange(ref elapsed, watch.Elapsed); barrier.Signal(); }, TimeSpan.FromMilliseconds(timeout)); Assert.True(barrier.Wait(tickInterval * 2 + timeout), $"Elapsed: {NanoTime.ToMilliseconds(elapsed)}, ticks interval: {tickInterval}, timeout: {timeout}."); }
/// <summary> /// Schedule a new callback with specified timeout in milliseconds. /// </summary> /// <param name="action">Callback function to be fired when timeout.</param> /// <returns>A callback wrapper which allow user to cancel timeout.</returns> public TimedCallback ScheduleTimeout(Action action, double milliseconds) { if (milliseconds < 0) { throw new ArgumentException("Expiry time cannot be negative.", "timeout"); } CheckTimerState(); var nanoTimeout = NanoTime.FromMilliseconds(milliseconds); var actualTimeout = time.Elapsed + nanoTimeout; var callback = new TimedCallback(action, actualTimeout, this); Interlocked.Increment(ref timeoutsCount); Interlocked.Increment(ref activeTimeoutsCount); ScheduleTimeoutImpl(callback, actualTimeout); return(callback); }
private void ReadInt96(byte[] data, SchemaElement schema, IList destination) { for (int i = 0; i < data.Length; i += 12) { if (!_options.TreatBigIntegersAsDates) { byte[] v96 = new byte[12]; Array.Copy(data, i, v96, 0, 12);; destination.Add(new BigInteger(v96)); } else { var nano = new NanoTime(data, i); DateTimeOffset dt = nano; destination.Add(dt); } } }
private void ScheduleTimeoutImpl(TimedCallback callback, long nanoseconds) { // TODO: Should always schedule to next tick var differredTimeout = nanoseconds + TicksInterval; var diff = ToWheelTicks(differredTimeout); var deadline = NanoTime.ToMilliseconds(CalculateDeadline()); var due = diff + deadline; HashedWheelSlot slot; if (diff < WHEEL_SIZE) { var _ = (due & WHEEL_MASK); slot = slots[0, due & WHEEL_MASK]; } else if (diff < 1 << (2 * WHEEL_BITS)) { var _ = ((due >> WHEEL_BITS) & WHEEL_MASK); slot = slots[1, (due >> WHEEL_BITS) & WHEEL_MASK]; } else if (diff < 1 << (3 * WHEEL_BITS)) { var _ = ((due >> 2 * WHEEL_BITS) & WHEEL_MASK); slot = slots[2, (due >> 2 * WHEEL_BITS) & WHEEL_MASK]; } else { if (diff > 0xffffffff) { diff = 0xffffffff; due = NanoTime.ToMilliseconds(diff + deadline); } var _ = ((due >> 3 * WHEEL_BITS) & WHEEL_MASK); slot = slots[3, (due >> 3 * WHEEL_BITS) & WHEEL_MASK]; } slot.Push(callback); }
/// <summary> /// Create a timer with specified tick interval and sleep policy. /// </summary> /// <param name="interval">ticks interval</param> /// <param name="policy">Sleep policy</param> public HashedWheelTimer(TimeSpan interval, SleepPolicy policy = SleepPolicy.Default) : this(policy) { TicksInterval = NanoTime.FromMilliseconds(interval.TotalMilliseconds); }