using System.Threading.Tasks;
using System.Collections.Generic;
using System.Collections.Concurrent;
public static async Task Main()
public static class Exercise1
private const int SEQUENCE_SIZE = 512;
private const int SUB_SEQUENCE_SIZE = 32;
private const int EXPECTED_RESULT_LENGTH = SEQUENCE_SIZE * 2048;
public static async ValueTask Run()
Console.WriteLine("Run started");
var sequenceOffsets = new int[SEQUENCE_SIZE / SUB_SEQUENCE_SIZE];
for (int i = 0; i < sequenceOffsets.Length; i++)
sequenceOffsets[i] = Random.Shared.Next(2048);
var database = new MockDatabase(sequenceOffsets, SUB_SEQUENCE_SIZE);
var values = await GetDatabaseSequence(database);
ValidateResult(values, sequenceOffsets);
Console.WriteLine("Run finished");
private static void ValidateResult(List<int> result, int[] sequenceOffsets)
if (result.Count < EXPECTED_RESULT_LENGTH)
throw new ArgumentException($"Expected list size of '{EXPECTED_RESULT_LENGTH}' but got '{result.Count}'");
for (int i = 0; i < EXPECTED_RESULT_LENGTH; i++)
var offset = sequenceOffsets[(i / SUB_SEQUENCE_SIZE) % sequenceOffsets.Length];
var expected = (i % SEQUENCE_SIZE) + offset;
if (result[i] != expected)
throw new ArgumentException($"Expected '{expected}' for index '{i}' but got '{result[i]}'");
private static async ValueTask<List<int>> GetDatabaseSequence(MockDatabase database)
var dbValues = new List<int>();
for (int i = 0; i < SEQUENCE_SIZE; i++)
var value = database.GetSequenceValue(i).AsTask().Result;
dbValues.AddRange(new List<int>() { value });
var result = new List<int>();
var numSequenceRepeats = EXPECTED_RESULT_LENGTH / SEQUENCE_SIZE;
for (int i = 0; i < numSequenceRepeats; i++)
result.AddRange(dbValues.Select(x => x).ToArray());
public class MockDatabase
private const int NUM_WORKER_THREADS = 4;
private const int REQUEST_TIMEOUT_MS = 250;
private readonly ConcurrentQueue<Request> requestQueue = new();
private readonly int[] sequenceOffsets;
private readonly int subSequenceSize;
public readonly int sequenceIndex;
public MockDatabase(int[] sequenceOffsets, int subSequenceSize)
this.sequenceOffsets = sequenceOffsets;
this.subSequenceSize = subSequenceSize;
for (int i = 0; i < NUM_WORKER_THREADS; i++)
private async ValueTask WorkerThread()
if (requestQueue.TryDequeue(out Request request))
var offset = sequenceOffsets[(request.sequenceIndex / subSequenceSize) % sequenceOffsets.Length];
request.result = request.sequenceIndex + offset;
public async ValueTask<int> GetSequenceValue(int sequenceIndex)
await Task.Delay(5 + Random.Shared.Next(2));
Request request = new(sequenceIndex);
requestQueue.Enqueue(request);
const int POLL_DELAY_MS = 1;
while (requestTimeMs < REQUEST_TIMEOUT_MS)
await Task.Delay(POLL_DELAY_MS);
requestTimeMs += POLL_DELAY_MS;
throw new TimeoutException();