Files
Studio/Packages/com.tivadar.best.http/Runtime/Shared/Database/MetadataService.cs

154 lines
4.4 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using Best.HTTP.Shared.Databases.MetadataIndexFinders;
using UnityEngine;
namespace Best.HTTP.Shared.Databases
{
public struct MetadataStats
{
public int min;
public int max;
public int count;
public int sum;
}
public abstract class MetadataService<MetadataType, ContentType> where MetadataType : Metadata, new()
{
public List<MetadataType> Metadatas { get; protected set; }
public IndexingService<ContentType, MetadataType> IndexingService { get; protected set; }
public IEmptyMetadataIndexFinder<MetadataType> EmptyMetadataIndexFinder { get; protected set; }
protected MetadataService(IndexingService<ContentType, MetadataType> indexingService, IEmptyMetadataIndexFinder<MetadataType> emptyMetadataIndexFinder)
{
this.IndexingService = indexingService;
this.EmptyMetadataIndexFinder = emptyMetadataIndexFinder;
this.Metadatas = new List<MetadataType>();
}
/// <summary>
/// Called when metadata loaded from file
/// </summary>
public virtual MetadataType CreateFrom(Stream stream)
{
var metadata = new MetadataType();
metadata.Index = this.Metadatas.Count;
metadata.LoadFrom(stream);
this.Metadatas.Add(metadata);
this.IndexingService.Index(metadata);
return metadata;
}
/// <summary>
/// Called by a concrete MetadataService implementation to create a new metadata
/// </summary>
protected MetadataType CreateDefault(ContentType content, int filePos, int length, Action<ContentType, MetadataType> setupCallback)
{
var metadata = new MetadataType();
metadata.FilePosition = filePos;
metadata.Length = length;
metadata.Index = this.EmptyMetadataIndexFinder.FindFreeIndex(this.Metadatas);
if (setupCallback != null)
setupCallback(content, metadata);
if (metadata.Index == this.Metadatas.Count)
this.Metadatas.Add(metadata);
else
this.Metadatas[metadata.Index] = metadata;
this.IndexingService.Index(metadata);
return metadata;
}
public void Remove(MetadataType metadata)
{
this.IndexingService.Remove(metadata);
// Mark metadata for deletion. Next time we save, it's not going to written out to disk.
metadata.MarkForDelete();
}
public void SaveTo(Stream stream)
{
stream.SetLength(0);
var optimizedIndexes = this.IndexingService.GetOptimizedIndexes();
if (optimizedIndexes != null)
{
foreach (var index in optimizedIndexes)
{
var metadata = this.Metadatas[index];
if (metadata.IsDeleted)
continue;
metadata.SaveTo(stream);
}
}
else
{
for (int i = 0; i < this.Metadatas.Count; ++i)
{
var metadata = this.Metadatas[i];
if (metadata.IsDeleted)
continue;
metadata.SaveTo(stream);
}
}
}
public void LoadFrom(Stream stream)
{
while (stream.Position < stream.Length)
CreateFrom(stream);
}
public virtual void Clear()
{
this.Metadatas.Clear();
this.IndexingService.Clear();
}
public MetadataStats GetStats()
{
int min = int.MaxValue;
int max = 0;
int sum = 0;
int count = 0;
foreach (var metadata in this.Metadatas)
{
if (metadata.IsDeleted)
continue;
if (metadata.Length > max)
max = metadata.Length;
if (metadata.Length < min)
min = metadata.Length;
sum += metadata.Length;
count++;
}
return new MetadataStats
{
count = count,
min = min,
max = max,
sum = sum
};
}
}
}