Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 85 additions & 12 deletions src/PureHDF/VOL/Native/API.Reading/NativeGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,27 @@ public IEnumerable<IH5Object> Children(H5LinkAccess linkAccess = default)
.Select(reference => reference.Dereference());
}

/// <summary>
/// Gets the number of children in this group without dereferencing them.
/// </summary>
/// <returns>The number of children in this group.</returns>
public ulong GetChildCount()
{
var linkInfoMessage = GetLinkInfoMessage();

if (!Context.Superblock.IsUndefinedAddress(linkInfoMessage.BTree2NameIndexAddress))
{
return linkInfoMessage.BTree2NameIndex.RootNodePointer.TotalRecordCount;
}

if (Context.Superblock.IsUndefinedAddress(linkInfoMessage.FractalHeapAddress))
{
return (ulong)Header.GetMessages<LinkMessage>().Count();
}

throw new NotSupportedException("The group does not use compact or indexed dense link storage.");
}

private bool InternalLinkExists(string path, H5LinkAccess linkAccess)
{
if (path == "/")
Expand Down Expand Up @@ -430,8 +451,16 @@ private IEnumerable<NativeNamedReference> EnumerateReferences(H5LinkAccess linkA
* A group is storing its links compactly when the fractal heap address
* in the Link Info Message is set to the "undefined address" value. */
else
{
linkMessages = Header.GetMessages<LinkMessage>();

if (lmessage.Flags.HasFlag(CreationOrderFlags.TrackCreationOrder))
{
linkMessages = linkMessages
.OrderBy(message => message.CreationOrder);
}
}

// build links
foreach (var linkMessage in linkMessages)
{
Expand All @@ -451,29 +480,73 @@ private IEnumerable<NativeNamedReference> EnumerateReferences(H5LinkAccess linkA
#region Link Message

private IEnumerable<LinkMessage> EnumerateLinkMessagesFromLinkInfoMessage(LinkInfoMessage infoMessage)
{
if (infoMessage.Flags.HasFlag(CreationOrderFlags.TrackCreationOrder))
return EnumerateLinkMessagesByCreationOrder(infoMessage);

return EnumerateLinkMessagesByName(infoMessage);
}

private IEnumerable<LinkMessage> EnumerateLinkMessagesByName(LinkInfoMessage infoMessage)
{
var fractalHeap = infoMessage.FractalHeap;
var btree2NameIndex = infoMessage.BTree2NameIndex;
var records = btree2NameIndex
.EnumerateRecords()
.ToList();

// local cache: indirectly accessed, non-filtered
List<BTree2Record01>? record01Cache = null;
BTree2Header<BTree2Record01>? record01Cache = null;

foreach (var record in btree2NameIndex.EnumerateRecords())
{
yield return ReadLinkMessage(fractalHeap, record.HeapId, ref record01Cache);
}
}

foreach (var record in records)
private IEnumerable<LinkMessage> EnumerateLinkMessagesByCreationOrder(LinkInfoMessage infoMessage)
{
if (Context.Superblock.IsUndefinedAddress(infoMessage.BTree2CreationOrderIndexAddress))
{
using var localDriver = new H5StreamDriver(new MemoryStream(record.HeapId), leaveOpen: false);
var heapId = FractalHeapId.Construct(Context, localDriver, fractalHeap);
return EnumerateLinkMessagesByName(infoMessage)
.OrderBy(message => message.CreationOrder);
}

yield return heapId.Read(driver =>
{
var message = LinkMessage.Decode(Context);
return message;
}, ref record01Cache);
return EnumerateLinkMessagesByCreationOrderIndex(infoMessage);
}

private IEnumerable<LinkMessage> EnumerateLinkMessagesByCreationOrderIndex(LinkInfoMessage infoMessage)
{
var fractalHeap = infoMessage.FractalHeap;
var btree2CreationOrder = infoMessage.BTree2CreationOrder;

// local cache: indirectly accessed, non-filtered
BTree2Header<BTree2Record01>? record01Cache = null;

foreach (var record in btree2CreationOrder.EnumerateRecords())
{
yield return ReadLinkMessage(fractalHeap, record.HeapId, ref record01Cache);
}
}

private LinkInfoMessage GetLinkInfoMessage()
{
var linkInfoMessages = Header.GetMessages<LinkInfoMessage>();

if (!linkInfoMessages.Any())
throw new Exception("No link information found in object header.");

if (linkInfoMessages.Count() != 1)
throw new Exception("There may be only a single link info message.");

return linkInfoMessages.First();
}

private LinkMessage ReadLinkMessage(FractalHeapHeader fractalHeap, byte[] heapIdBytes, ref BTree2Header<BTree2Record01>? record01Cache)
{
using var localDriver = new H5StreamDriver(new MemoryStream(heapIdBytes), leaveOpen: false);
var heapId = FractalHeapId.Construct(Context, localDriver, fractalHeap);

return heapId.Read(driver => LinkMessage.Decode(Context), ref record01Cache);
}

private bool TryGetLinkMessageFromLinkInfoMessage(LinkInfoMessage linkInfoMessage,
string name,
[NotNullWhen(returnValue: true)] out LinkMessage? linkMessage)
Expand Down
7 changes: 2 additions & 5 deletions src/PureHDF/VOL/Native/API.Reading/NativeObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,16 +186,13 @@ private IEnumerable<AttributeMessage> EnumerateAttributeMessagesFromAttributeInf
AttributeInfoMessage attributeInfoMessage)
{
var btree2NameIndex = attributeInfoMessage.BTree2NameIndex;
var records = btree2NameIndex
.EnumerateRecords()
.ToList();

var fractalHeap = attributeInfoMessage.FractalHeap;

// local cache: indirectly accessed, non-filtered
List<BTree2Record01>? record01Cache = null;
BTree2Header<BTree2Record01>? record01Cache = null;

foreach (var record in records)
foreach (var record in btree2NameIndex.EnumerateRecords())
{
// TODO: duplicate1_of_3
using var localDriver = new H5StreamDriver(new MemoryStream(record.HeapId), leaveOpen: false);
Expand Down
16 changes: 8 additions & 8 deletions src/PureHDF/VOL/Native/Core.Reading/NativeCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ internal static class NativeCache

static NativeCache()
{
_globalHeapMap = new ConcurrentDictionary<H5DriverBase, Dictionary<ulong, GlobalHeapCollection>>();
_fileMap = new ConcurrentDictionary<H5DriverBase, Dictionary<string, NativeFile>>();
_globalHeapMap = new ConcurrentDictionary<H5DriverBase, ConcurrentDictionary<ulong, GlobalHeapCollection>>();
_fileMap = new ConcurrentDictionary<H5DriverBase, ConcurrentDictionary<string, NativeFile>>();
}

#endregion
Expand Down Expand Up @@ -41,7 +41,7 @@ public static void Clear(H5DriverBase driver)

#region Global Heap

private static readonly ConcurrentDictionary<H5DriverBase, Dictionary<ulong, GlobalHeapCollection>> _globalHeapMap;
private static readonly ConcurrentDictionary<H5DriverBase, ConcurrentDictionary<ulong, GlobalHeapCollection>> _globalHeapMap;

public static GlobalHeapCollection GetGlobalHeapObject(
NativeReadContext context,
Expand All @@ -50,8 +50,8 @@ public static GlobalHeapCollection GetGlobalHeapObject(
{
if (!_globalHeapMap.TryGetValue(context.Driver, out var addressToCollectionMap))
{
addressToCollectionMap = new Dictionary<ulong, GlobalHeapCollection>();
_globalHeapMap.AddOrUpdate(context.Driver, addressToCollectionMap, (_, oldAddressToCollectionMap) => addressToCollectionMap);
addressToCollectionMap = new ConcurrentDictionary<ulong, GlobalHeapCollection>();
_globalHeapMap.AddOrUpdate(context.Driver, addressToCollectionMap, (_, oldAddressToCollectionMap) => oldAddressToCollectionMap);
}

if (!addressToCollectionMap.TryGetValue(address, out var collection))
Expand All @@ -74,7 +74,7 @@ public static GlobalHeapCollection GetGlobalHeapObject(

#region File Handles

private static readonly ConcurrentDictionary<H5DriverBase, Dictionary<string, NativeFile>> _fileMap;
private static readonly ConcurrentDictionary<H5DriverBase, ConcurrentDictionary<string, NativeFile>> _fileMap;

public static NativeFile GetNativeFile(H5DriverBase driver, string absoluteFilePath)
{
Expand All @@ -86,8 +86,8 @@ public static NativeFile GetNativeFile(H5DriverBase driver, string absoluteFileP

if (!_fileMap.TryGetValue(driver, out var pathToNativeFileMap))
{
pathToNativeFileMap = new Dictionary<string, NativeFile>();
_fileMap.AddOrUpdate(driver, pathToNativeFileMap, (_, oldPathToNativeFileMap) => pathToNativeFileMap);
pathToNativeFileMap = new ConcurrentDictionary<string, NativeFile>();
_fileMap.AddOrUpdate(driver, pathToNativeFileMap, (_, oldPathToNativeFileMap) => oldPathToNativeFileMap);
}

if (!pathToNativeFileMap.TryGetValue(uri.AbsoluteUri, out var nativeFile))
Expand Down
14 changes: 6 additions & 8 deletions src/PureHDF/VOL/Native/FileFormat/Level1/BTree2/BTree2Header.cs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ public IEnumerable<T> EnumerateRecords()
return EnumerateRecords(rootNode, Depth);

else
return new List<T>();
return Enumerable.Empty<T>();
}

private IEnumerable<T> EnumerateRecords(BTree2Node<T> node, ushort nodeLevel)
Expand All @@ -296,18 +296,12 @@ private IEnumerable<T> EnumerateRecords(BTree2Node<T> node, ushort nodeLevel)

if (internalNode is not null)
{
var records = node.Records
.Cast<T>()
.ToList();
var records = internalNode.Records;

var nodePointers = internalNode.NodePointers;

for (int i = 0; i < nodePointers.Length; i++)
{
// there is one more node pointer than records
if (i < records.Count)
yield return records[i];

var nodePointer = nodePointers[i];
Context.Driver.SeekRelativeToBaseAddress((long)nodePointer.Address);
var childNodeLevel = (ushort)(nodeLevel - 1);
Expand Down Expand Up @@ -341,6 +335,10 @@ private IEnumerable<T> EnumerateRecords(BTree2Node<T> node, ushort nodeLevel)
{
yield return record;
}

// there is one more node pointer than records
if (i < records.Length)
yield return records[i];
}
}
// leaf node
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ internal static FractalHeapId Construct(
public T Read<T>(Func<H5DriverBase, T> func)
{
// TODO: Is there a better way?
List<BTree2Record01>? cache = null;
BTree2Header<BTree2Record01>? cache = null;
return Read(func, ref cache);
}

public abstract T Read<T>(
Func<H5DriverBase, T> func,
[AllowNull] ref List<BTree2Record01> record01Cache);
[AllowNull] ref BTree2Header<BTree2Record01> record01Cache);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,22 @@ internal static HugeObjectsFractalHeapIdSubType1 Decode(

public override T Read<T>(
Func<H5DriverBase, T> func,
[AllowNull] ref List<BTree2Record01> record01Cache)
[AllowNull] ref BTree2Header<BTree2Record01> record01Cache)
{
var driver = Context.Driver;

// huge objects b-tree v2
if (record01Cache is null)
{
driver.SeekRelativeToBaseAddress((long)HeapHeader.HugeObjectsBTree2Address);
var hugeBtree2 = BTree2Header<BTree2Record01>.Decode(Context, DecodeRecord01);
record01Cache = hugeBtree2.EnumerateRecords().ToList();
record01Cache = BTree2Header<BTree2Record01>.Decode(Context, DecodeRecord01);
}

var hugeRecord = record01Cache.FirstOrDefault(record => record.HugeObjectId == BTree2Key);
var success = record01Cache.TryFindRecord(out var hugeRecord, record => BTree2Key.CompareTo(record.HugeObjectId));

if (!success)
throw new Exception("Could not find huge fractal heap object.");

driver.SeekRelativeToBaseAddress((long)hugeRecord.HugeObjectAddress);

return func(driver);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ ulong BTree2Key

public override T Read<T>(
Func<H5DriverBase, T> func,
[AllowNull] ref List<BTree2Record01> record01Cache)
[AllowNull] ref BTree2Header<BTree2Record01> record01Cache)
{
throw new Exception("Filtered data is not yet supported.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static HugeObjectsFractalHeapIdSubType3 Decode(NativeReadContext context,
}
public override T Read<T>(
Func<H5DriverBase, T> func,
[AllowNull] ref List<BTree2Record01> record01Cache)
[AllowNull] ref BTree2Header<BTree2Record01> record01Cache)
{
Driver.SeekRelativeToBaseAddress((long)Address);
return func(Driver);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static HugeObjectsFractalHeapIdSubType4 Decode(

public override T Read<T>(
Func<H5DriverBase, T> func,
[AllowNull] ref List<BTree2Record01> record01Cache)
[AllowNull] ref BTree2Header<BTree2Record01> record01Cache)
{
throw new Exception("Filtered data is not yet supported.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public static ManagedObjectsFractalHeapId Decode(

public override T Read<T>(
Func<H5DriverBase, T> func,
[AllowNull] ref List<BTree2Record01> record01Cache)
[AllowNull] ref BTree2Header<BTree2Record01> record01Cache)
{
var address = Header.GetAddress(this);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static TinyObjectsFractalHeapIdSubType1 Decode(

public override T Read<T>(
Func<H5DriverBase, T> func,
[AllowNull] ref List<BTree2Record01> record01Cache)
[AllowNull] ref BTree2Header<BTree2Record01> record01Cache)
{
using var driver = new H5StreamDriver(new MemoryStream(Data), leaveOpen: false);
return func.Invoke(driver);
Expand Down
Loading