2024-07-25 08:10:11 +00:00
|
|
|
|
using CodexPlugin;
|
|
|
|
|
using DistTestCore;
|
2024-04-22 09:17:47 +00:00
|
|
|
|
using NUnit.Framework;
|
2024-04-19 09:40:32 +00:00
|
|
|
|
using Utils;
|
|
|
|
|
|
|
|
|
|
namespace CodexTests.ScalabilityTests
|
|
|
|
|
{
|
|
|
|
|
[TestFixture]
|
|
|
|
|
public class MultiPeerDownloadTests : AutoBootstrapDistTest
|
|
|
|
|
{
|
|
|
|
|
[Test]
|
2024-04-22 09:17:47 +00:00
|
|
|
|
[DontDownloadLogs]
|
|
|
|
|
[UseLongTimeouts]
|
2024-04-19 09:52:39 +00:00
|
|
|
|
[Combinatorial]
|
|
|
|
|
public void MultiPeerDownload(
|
|
|
|
|
[Values(5, 10, 20)] int numberOfHosts,
|
|
|
|
|
[Values(100, 1000)] int fileSize
|
|
|
|
|
)
|
2024-04-19 09:40:32 +00:00
|
|
|
|
{
|
2024-07-25 08:10:11 +00:00
|
|
|
|
var hosts = StartCodex(numberOfHosts, s => s.WithName("host").WithLogLevel(CodexLogLevel.Trace));
|
2024-04-19 09:52:39 +00:00
|
|
|
|
var file = GenerateTestFile(fileSize.MB());
|
2024-07-25 08:10:11 +00:00
|
|
|
|
|
|
|
|
|
var uploadTasks = hosts.Select(h =>
|
|
|
|
|
{
|
|
|
|
|
return Task.Run(() =>
|
|
|
|
|
{
|
|
|
|
|
return h.UploadFile(file);
|
|
|
|
|
});
|
|
|
|
|
}).ToArray();
|
|
|
|
|
|
|
|
|
|
Task.WaitAll(uploadTasks);
|
|
|
|
|
var cid = new ContentId(uploadTasks.Select(t => t.Result.Id).Distinct().Single());
|
2024-04-19 09:40:32 +00:00
|
|
|
|
|
|
|
|
|
var uploadLog = Ci.DownloadLog(hosts[0]);
|
2024-04-22 09:17:47 +00:00
|
|
|
|
var expectedNumberOfBlocks = RoundUp(fileSize.MB().SizeInBytes, 64.KB().SizeInBytes) + 1; // +1 for manifest block.
|
2024-04-19 09:40:32 +00:00
|
|
|
|
var blockCids = uploadLog
|
2024-07-24 14:06:45 +00:00
|
|
|
|
.FindLinesThatContain("Block Stored")
|
2024-04-19 09:40:32 +00:00
|
|
|
|
.Select(s =>
|
|
|
|
|
{
|
2024-07-25 08:10:11 +00:00
|
|
|
|
var line = CodexLogLine.Parse(s)!;
|
|
|
|
|
return line.Attributes["cid"];
|
2024-04-19 09:40:32 +00:00
|
|
|
|
})
|
|
|
|
|
.ToArray();
|
|
|
|
|
|
2024-04-22 09:17:47 +00:00
|
|
|
|
Assert.That(blockCids.Length, Is.EqualTo(expectedNumberOfBlocks));
|
|
|
|
|
|
2024-04-19 09:40:32 +00:00
|
|
|
|
|
2024-07-25 08:10:11 +00:00
|
|
|
|
|
|
|
|
|
var client = StartCodex(s => s.WithName("client").WithLogLevel(CodexLogLevel.Trace));
|
2024-04-19 09:40:32 +00:00
|
|
|
|
var resultFile = client.DownloadContent(cid);
|
|
|
|
|
resultFile!.AssertIsEqual(file);
|
|
|
|
|
|
|
|
|
|
var downloadLog = Ci.DownloadLog(client);
|
|
|
|
|
var host = string.Empty;
|
2024-07-25 08:10:11 +00:00
|
|
|
|
var blockAddressHostMap = new Dictionary<string, List<string>>();
|
|
|
|
|
downloadLog
|
|
|
|
|
.IterateLines(s =>
|
2024-04-19 09:40:32 +00:00
|
|
|
|
{
|
2024-07-25 08:10:11 +00:00
|
|
|
|
var line = CodexLogLine.Parse(s)!;
|
|
|
|
|
var peer = line.Attributes["peer"];
|
|
|
|
|
var blockAddresses = line.Attributes["blocks"];
|
2024-04-19 09:40:32 +00:00
|
|
|
|
|
2024-07-25 08:10:11 +00:00
|
|
|
|
AddBlockAddresses(peer, blockAddresses, blockAddressHostMap);
|
|
|
|
|
|
|
|
|
|
}, thatContain: "Received blocks from peer");
|
2024-04-19 09:40:32 +00:00
|
|
|
|
|
2024-07-25 08:10:11 +00:00
|
|
|
|
var totalFetched = blockAddressHostMap.Count(p => p.Value.Any());
|
|
|
|
|
PrintFullMap(blockAddressHostMap);
|
|
|
|
|
//PrintOverview(blockCidHostMap);
|
2024-04-22 09:17:47 +00:00
|
|
|
|
|
|
|
|
|
Log("Expected number of blocks: " + expectedNumberOfBlocks);
|
|
|
|
|
Log("Total number of block CIDs found in dataset + manifest block: " + blockCids.Length);
|
|
|
|
|
Log("Total blocks fetched by hosts: " + totalFetched);
|
|
|
|
|
Assert.That(totalFetched, Is.EqualTo(expectedNumberOfBlocks));
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-25 08:10:11 +00:00
|
|
|
|
private void AddBlockAddresses(string peer, string blockAddresses, Dictionary<string, List<string>> blockAddressHostMap)
|
|
|
|
|
{
|
|
|
|
|
// Single line can contain multiple block addresses.
|
|
|
|
|
var tokens = blockAddresses.Split(",", StringSplitOptions.RemoveEmptyEntries).ToList();
|
|
|
|
|
while (tokens.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
if (tokens.Count == 1)
|
|
|
|
|
{
|
|
|
|
|
AddBlockAddress(peer, tokens[0], blockAddressHostMap);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var blockAddress = $"{tokens[0]}, {tokens[1]}";
|
|
|
|
|
tokens.RemoveRange(0, 2);
|
|
|
|
|
|
|
|
|
|
AddBlockAddress(peer, blockAddress, blockAddressHostMap);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AddBlockAddress(string peer, string blockAddress, Dictionary<string, List<string>> blockAddressHostMap)
|
|
|
|
|
{
|
|
|
|
|
if (blockAddressHostMap.ContainsKey(blockAddress))
|
|
|
|
|
{
|
|
|
|
|
blockAddressHostMap[blockAddress].Add(peer);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
blockAddressHostMap[blockAddress] = new List<string> { peer };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void PrintOverview(Dictionary<string, List<string>> blockAddressHostMap)
|
2024-04-22 09:17:47 +00:00
|
|
|
|
{
|
|
|
|
|
var overview = new Dictionary<string, int>();
|
2024-07-25 08:10:11 +00:00
|
|
|
|
foreach (var pair in blockAddressHostMap)
|
2024-04-22 09:17:47 +00:00
|
|
|
|
{
|
2024-07-25 08:10:11 +00:00
|
|
|
|
foreach (var host in pair.Value)
|
|
|
|
|
{
|
|
|
|
|
if (!overview.ContainsKey(host)) overview.Add(host, 1);
|
|
|
|
|
else overview[host]++;
|
|
|
|
|
}
|
2024-04-22 09:17:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-04-19 09:40:32 +00:00
|
|
|
|
Log("Blocks fetched per host:");
|
2024-04-22 09:17:47 +00:00
|
|
|
|
foreach (var pair in overview)
|
2024-04-19 09:40:32 +00:00
|
|
|
|
{
|
|
|
|
|
Log($"Host: {pair.Key} = {pair.Value}");
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-04-22 09:17:47 +00:00
|
|
|
|
|
2024-07-25 08:10:11 +00:00
|
|
|
|
private void PrintFullMap(Dictionary<string, List<string>> blockAddressHostMap)
|
2024-04-22 09:17:47 +00:00
|
|
|
|
{
|
|
|
|
|
Log("Per block, host it was fetched from:");
|
2024-07-25 08:10:11 +00:00
|
|
|
|
foreach (var pair in blockAddressHostMap)
|
2024-04-22 09:17:47 +00:00
|
|
|
|
{
|
2024-07-25 08:10:11 +00:00
|
|
|
|
var hostStr = $"[{string.Join(",", pair.Value)}]";
|
|
|
|
|
Log($"blockAddress: {pair.Key} = {hostStr}");
|
2024-04-22 09:17:47 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private long RoundUp(long filesize, long blockSize)
|
|
|
|
|
{
|
|
|
|
|
double f = filesize;
|
|
|
|
|
double b = blockSize;
|
|
|
|
|
|
|
|
|
|
var result = Math.Ceiling(f / b);
|
|
|
|
|
return Convert.ToInt64(result);
|
|
|
|
|
}
|
2024-04-19 09:40:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|