forked from ddrilling/AsbCloudServer
#7579139 первая версия кеша готова. Не применена и не протестирована.
This commit is contained in:
parent
95cf8dbd07
commit
64641c5bc3
@ -18,10 +18,6 @@
|
||||
<EditorConfigFiles Remove="D:\Source\AsbCloudApp\Services\.editorconfig" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="D:\Source\AsbCloudApp\Services\.editorconfig" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AsbCloudDb\AsbCloudDb.csproj" />
|
||||
</ItemGroup>
|
||||
|
@ -82,7 +82,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<IEnumerable<TDto>> GetAsync(int idWell,
|
||||
DateTime dateBegin = default, double intervalSec = 600d,
|
||||
int approxPointsCount = 1024, CancellationToken token = default)
|
||||
|
@ -1,23 +1,114 @@
|
||||
using AsbCloudDb.Model;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using AsbCloudApp.Services;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Mapster;
|
||||
|
||||
#nullable enable
|
||||
namespace AsbCloudInfrastructure.Services.SAUB
|
||||
{
|
||||
public class TelemetryDataCache
|
||||
public class TelemetryDataCache<TDto, TEntity>
|
||||
where TDto : AsbCloudApp.Data.ITelemetryData
|
||||
where TEntity : class, ITelemetryData
|
||||
{
|
||||
private readonly ConcurrentDictionary<int, Dictionary<int, IEnumerable>> caches;
|
||||
private static TelemetryDataCache? instance;
|
||||
private const int activeWellCapacity = 24 * 60 * 60;
|
||||
private const int doneWellCapacity = 65 * 60;
|
||||
|
||||
private readonly ConcurrentDictionary<int, CyclycArray<TDto>> caches;
|
||||
|
||||
public TelemetryDataCache(IAsbCloudDbContext db)
|
||||
{
|
||||
caches = new ();
|
||||
LoadCaches(db);
|
||||
}
|
||||
|
||||
private void LoadCaches(IAsbCloudDbContext db)
|
||||
{
|
||||
Well[] wells = db.Set<Well>()
|
||||
.Include(well => well.Telemetry)
|
||||
.Where(well => well.IdTelemetry != null)
|
||||
.ToArray();
|
||||
|
||||
foreach (Well well in wells)
|
||||
{
|
||||
var capacity = well.IdState == 1
|
||||
? activeWellCapacity
|
||||
: doneWellCapacity;
|
||||
|
||||
var idTelemetry = well.IdTelemetry!.Value;
|
||||
var hoursOffset = well.Timezone.Hours;
|
||||
|
||||
IEnumerable<TDto> cacheItemData = GetCacheDataFromDb(db, idTelemetry, capacity, hoursOffset);
|
||||
var cacheItem = new CyclycArray<TDto>(capacity);
|
||||
cacheItem.AddRange(cacheItemData);
|
||||
caches.TryAdd(idTelemetry, cacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<TDto> GetCacheDataFromDb(IAsbCloudDbContext db, int idTelemetry, int capacity, double hoursOffset)
|
||||
{
|
||||
var entities = db.Set<TEntity>()
|
||||
.Where(i => i.IdTelemetry == idTelemetry)
|
||||
.OrderByDescending(i => i.DateTime)
|
||||
.Take(capacity)
|
||||
.ToArray()
|
||||
.OrderBy(i => i.DateTime);
|
||||
|
||||
var dtos = entities.Select(entity => {
|
||||
var dto = entity.Adapt<TDto>();
|
||||
dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset);
|
||||
return dto;
|
||||
});
|
||||
|
||||
return dtos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавить элементы в кеш
|
||||
/// </summary>
|
||||
/// <param name="idTelemetry"></param>
|
||||
/// <param name="range"></param>
|
||||
public void AddRange(int idTelemetry, IEnumerable<TDto> range)
|
||||
{
|
||||
var cacheItem = caches.GetOrAdd(idTelemetry, _ => new CyclycArray<TDto>(activeWellCapacity));
|
||||
var newItems = range
|
||||
.OrderBy(i => i.DateTime);
|
||||
foreach (var item in newItems)
|
||||
item.IdTelemetry = idTelemetry;
|
||||
cacheItem.AddRange(newItems);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить данные из кеша. <br/>
|
||||
/// Если dateBegin меньше минимального элемента в кеше, то вернется null.
|
||||
/// Даже если intervalSec частично перекрыт данными из кеша.
|
||||
/// </summary>
|
||||
/// <param name="idTelemetry"></param>
|
||||
/// <param name="dateBegin"></param>
|
||||
/// <param name="intervalSec"></param>
|
||||
/// <param name="approxPointsCount">кол-во элементов до которых эти данные прореживаются</param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<TDto>? GetOrDefault(int idTelemetry, DateTime dateBegin, double intervalSec = 600d, int approxPointsCount = 1024)
|
||||
{
|
||||
if(!caches.TryGetValue(idTelemetry, out CyclycArray<TDto>? cacheItem))
|
||||
return null;
|
||||
|
||||
if (cacheItem is null || cacheItem[0].DateTime > dateBegin)
|
||||
return null;
|
||||
|
||||
var dateEnd = dateBegin.AddSeconds(intervalSec);
|
||||
var items = cacheItem
|
||||
.Where(i => i.DateTime >= dateBegin && i.DateTime <= dateEnd);
|
||||
|
||||
var ratio = items.Count() / approxPointsCount;
|
||||
if (ratio > 1)
|
||||
items = items
|
||||
.Where((_, index) => index % ratio == 0);
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
}
|
||||
#nullable disable
|
Loading…
Reference in New Issue
Block a user