Esempio n. 1
0
        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;
            }
        }