internal DataCenterElement(DataCenter center, DataCenterAddress address) { ushort attrCount; ushort childCount; DataCenterAddress attrAddr; DataCenterAddress childAddr; try { center.Lock.EnterReadLock(); if (center.IsDisposed) { throw new ObjectDisposedException(center.GetType().FullName); } var reader = center.Elements.GetReader(address); var nameIndex = reader.ReadUInt16() - 1; if (nameIndex == -1) { throw new DataCenterPlaceholderException(); } if (nameIndex >= center.Names.Count) { throw new InvalidDataException(); } Name = center.Names[nameIndex]; reader.ReadUInt16(); attrCount = reader.ReadUInt16(); childCount = reader.ReadUInt16(); attrAddr = DataCenter.ReadAddress(reader); childAddr = DataCenter.ReadAddress(reader); } finally { center.Lock.ExitReadLock(); } _attributes = new Lazy <IReadOnlyList <DataCenterAttribute> >(() => { var attributes = new List <DataCenterAttribute>(); try { center.Lock.EnterReadLock(); if (center.IsDisposed) { throw new ObjectDisposedException(center.GetType().FullName); } for (var i = 0; i < attrCount; i++) { var addr = new DataCenterAddress(attrAddr.SegmentIndex, (ushort)(attrAddr.ElementIndex + i)); var attrReader = center.Attributes.GetReader(addr); var attrNameIndex = attrReader.ReadUInt16() - 1; if (attrNameIndex >= center.Names.Count) { throw new InvalidDataException(); } var typeCode = (DataCenterTypeCode)attrReader.ReadUInt16(); if (typeCode != DataCenterTypeCode.Int32 && typeCode != DataCenterTypeCode.Single && typeCode != DataCenterTypeCode.Boolean) { typeCode = DataCenterTypeCode.String; } var primitiveValue = attrReader.ReadInt32(); string stringValue = null; if (typeCode == DataCenterTypeCode.String) { attrReader.Position -= sizeof(int); var strAddr = DataCenter.ReadAddress(attrReader); stringValue = center.GetString(strAddr); } attributes.Add(new DataCenterAttribute( center.Names[attrNameIndex], typeCode, primitiveValue, stringValue)); } } finally { center.Lock.ExitReadLock(); } return(attributes); }); _children = new Lazy <IReadOnlyList <DataCenterElement> >(() => { var children = new List <DataCenterElement>(); for (var i = 0; i < childCount; i++) { var addr = new DataCenterAddress(childAddr.SegmentIndex, (ushort)(childAddr.ElementIndex + i)); try { children.Add(new DataCenterElement(center, addr) { Parent = this, }); } catch (DataCenterPlaceholderException) { } } return(children); }); }
public DataCenterStringTable(DataCenterSegmentedRegion data, DataCenterSegmentedSimpleRegion table, DataCenterSimpleRegion addresses, bool names, DataCenterStringOptions options) { var count = (int)addresses.Count; _intern = options.HasFlag(DataCenterStringOptions.Intern); _strings = new ConcurrentDictionary <DataCenterAddress, string>( Environment.ProcessorCount, count); var lazy = options.HasFlag(DataCenterStringOptions.Lazy); // We only need the address list if we are eagerly loading strings // and thus verifying the integrity of the regions, or if we are // loading the names table which is always accessed by index. The // values table is never accessed by index. if (names || !lazy) { var addrs = new List <DataCenterAddress>(count); for (uint i = 0; i < addresses.Count; i++) { var addr = DataCenter.ReadAddress(addresses.GetReader(i)); if (addr == DataCenterAddress.Invalid) { throw new InvalidDataException($"String address {addr} is invalid."); } addrs.Add(addr); } _addresses = addrs; } if (!lazy) { foreach (var(i, segment) in table.Segments.WithIndex()) { long last = -1; for (uint j = 0; j < segment.Count; j++) { var reader = segment.GetReader(j); // This hash only has a tiny amount of collisions in a // typical data center. var hash = reader.ReadUInt32(); if (hash < last) { throw new InvalidDataException( $"String hash {hash} is less than previous hash {last}."); } last = hash; var bucket = (hash ^ hash >> 16) % table.Segments.Count; if (bucket != i) { throw new InvalidDataException( $"String bucket index {i} does not match expected index {bucket}."); } // This includes the NUL character. var length = reader.ReadUInt32() - 1; var index = reader.ReadUInt32() - 1; if (index >= _addresses.Count) { throw new InvalidDataException( $"String index {index} is greater than {_addresses.Count}."); } var address1 = DataCenter.ReadAddress(reader); var address2 = _addresses[(int)index]; if (address1 != address2) { throw new InvalidDataException( $"String address {address1} does not match expected address {address2}."); } var value = data.GetReader(address1).ReadString(); if (value.Length != length) { throw new InvalidDataException( $"String length {value.Length} does not match recorded length {length}."); } if (!_strings.TryAdd(address1, _intern ? string.Intern(value) : value)) { throw new InvalidDataException( $"String address {address1} already added to the table."); } } } } else { _data = data; } }