DSInternals/Src/DSInternals.DataStore/AttributeMetadataCollection.cs

157 lines
5.4 KiB
C#
Raw Normal View History

2015-12-26 22:44:43 +00:00
using DSInternals.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace DSInternals.DataStore
{
public class AttributeMetadataCollection
2015-12-26 22:44:43 +00:00
{
private const int guidSize = 16;
private const int entrySize = 3 * sizeof(long) + 2 * sizeof(int) + guidSize;
private const int HeaderSize = 2 * sizeof(long); // Structure: | Unknown | Number of Entries | Entries |
private const long DefaultUnknownValue = 1;
2015-12-26 22:44:43 +00:00
public long Unknown
{
get;
private set;
}
2015-12-26 22:44:43 +00:00
public int Count
{
get
{
return this.InnerList?.Count ?? 0;
}
}
public IList<int> Attributes
{
get
{
return this.InnerList?.Keys;
2015-12-26 22:44:43 +00:00
}
}
/// <summary>
/// Holds a list of attribute metadata sorted by attribute ID.
/// </summary>
protected SortedList<int,AttributeMetadata> InnerList
2015-12-26 22:44:43 +00:00
{
get;
private set;
}
2015-12-26 22:44:43 +00:00
public AttributeMetadataCollection() : this(null) { }
2015-12-26 22:44:43 +00:00
public AttributeMetadataCollection(byte[] buffer)
{
if (buffer == null)
2015-12-26 22:44:43 +00:00
{
// Initialize an empty collection
this.Unknown = DefaultUnknownValue;
this.InnerList = new SortedList<int, AttributeMetadata>();
2015-12-26 22:44:43 +00:00
return;
}
Validator.AssertMinLength(buffer, HeaderSize, nameof(buffer));
using (Stream stream = new MemoryStream(buffer))
2015-12-26 22:44:43 +00:00
{
using (BinaryReader reader = new BinaryReader(stream))
2015-12-26 22:44:43 +00:00
{
// Read structure and validate header
2015-12-26 22:44:43 +00:00
this.Unknown = reader.ReadInt64();
long numEntries = reader.ReadInt64();
long expectedBufferSize = CalculateBinarySize(numEntries);
Validator.AssertLength(buffer, expectedBufferSize, nameof(buffer));
// Read all entries
this.InnerList = new SortedList<int, AttributeMetadata>((int)numEntries);
for (int i = 1; i <= numEntries; i++)
2015-12-26 22:44:43 +00:00
{
int attributeId = reader.ReadInt32();
int version = reader.ReadInt32();
long timestamp = reader.ReadInt64();
Guid originatingDSA = new Guid(reader.ReadBytes(16));
long originatingUSN = reader.ReadInt64();
long localUSN = reader.ReadInt64();
var entry = new AttributeMetadata(version, timestamp, originatingDSA, originatingUSN, localUSN);
try
{
this.InnerList.Add(attributeId, entry);
}
catch(ArgumentException)
{
// An element with the same key already exists.
// We will simply ignore duplicate values and thus remove them on save.
}
2015-12-26 22:44:43 +00:00
}
}
}
}
public void Update(int attributeId, Guid invocationId, DateTime time, long usn)
{
this.InnerList.TryGetValue(attributeId, out AttributeMetadata entry);
if (entry != null)
2015-12-26 22:44:43 +00:00
{
// This attribute is already contained in the list, so we just update it
entry.Update(invocationId, time, usn);
2015-12-26 22:44:43 +00:00
}
else
{
// This is a newly added attribute
entry = new AttributeMetadata(invocationId, time, usn);
this.InnerList.Add(attributeId, entry);
2015-12-26 22:44:43 +00:00
}
}
public byte[] ToByteArray()
{
byte[] buffer = new byte[CalculateBinarySize(this.Count)];
using (MemoryStream stream = new MemoryStream(buffer))
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(this.Unknown);
2015-12-26 22:44:43 +00:00
// Important: Write Count as 64-bit and not 32-bit:
writer.Write((long)this.Count);
foreach (var entry in this.InnerList)
2015-12-26 22:44:43 +00:00
{
writer.Write(entry.Key);
writer.Write(entry.Value.Version);
writer.Write(entry.Value.LastOriginatingChangeTimestamp);
writer.Write(entry.Value.LastOriginatingInvocationId.ToByteArray());
writer.Write(entry.Value.OriginatingChangeUsn);
writer.Write(entry.Value.LocalChangeUsn);
2015-12-26 22:44:43 +00:00
}
}
}
return buffer;
}
public override string ToString()
{
var text = new StringBuilder();
foreach (var entry in InnerList)
{
text.AppendFormat("AttId: {0}, ", entry.Key);
text.AppendLine(entry.Value.ToString());
2015-12-26 22:44:43 +00:00
}
return text.ToString();
}
private static long CalculateBinarySize(long numEntries)
{
// Unknown Value + Entry Count + Entries
return 2 * sizeof(long) + numEntries * entrySize;
}
}
}