protected void Commit(int id,
                              RegMemElem17 mem,
                              RegRtElem17 rtxOrRtf)
        {
            var member = _registry.Get(id);

            try
            {
                if (member == null)
                {
                    member = _registry.CreateInternal(id);

                    SetupMember(member, mem, rtxOrRtf);
                }

                else
                {
                    UpdateMember(member, mem, rtxOrRtf);
                }
            }
            finally
            {
                _onMemberCreatedOrUpdated(member);
            }
        }
        public void CommitFromMemory(
            IRegistryFileDescriptor registryFileDesc,
            SparseClusteredArray <byte> memSCA,
            SparseClusteredArray <byte> rtxSCA)
        {
            memSCA.Lock.EnterUpgradeableReadLock();
            rtxSCA.Lock.EnterUpgradeableReadLock();

            try
            {
                foreach (var memStream in memSCA.GetStreams())
                {
                    var memElems = memStream.StreamToStruct <RegMemElem17, RegMemElem17>(
                        RegMemElem17.SizeOfMemElem,
                        e => e
                        );

                    foreach (var memElemKeyValue in memElems.OrderBy(kv => kv.Value.rtxOffset))
                    {
                        var id      = memElemKeyValue.Key;
                        var memElem = memElemKeyValue.Value;

                        var lower = memElem.rtxOffset - 1;
                        var upper = memElem.rtxOffset + memElem.rtxLength - 2;

                        if (upper < lower || upper < 0)
                        {
                            LogTo.Warning($"({registryFileDesc.RegistryName}) Invalid rtx offsets, upper: {upper}, lower: {lower}");
                            continue;
                        }

                        SparseClusteredArray <byte> .Bounds rtxBounds = new SparseClusteredArray <byte> .Bounds(
                            lower,
                            upper
                            );

                        using (var rtStream = rtxSCA.GetSubsetStream(rtxBounds))
                        {
                            RegRtElem17 rtxElem = default;

                            if (rtStream != null)
                            {
                                rtxElem = ParseRtStream(rtStream,
                                                        memElem);
                            }

                            Commit(id, memElem, rtxElem);
                        }
                    }
                }

                memSCA.Clear();
                rtxSCA.Clear();
            }
            finally
            {
                memSCA.Lock.ExitUpgradeableReadLock();
                rtxSCA.Lock.ExitUpgradeableReadLock();
            }
        }
        public virtual void SetupMember(RegistryMemberBase member, RegMemElem17 mem, RegRtElem17 rt)
        {
            member.UseCount = mem.useCount;

            member.LinkType = (RegistryLinkType)mem.linkType;

            member.RtxId     = rt.no;
            member.RtxOffset = mem.rtxOffset;
            member.RtxLength = mem.rtxLength;

            if (rt.value != null)
            {
                member.RtxValue = Encoding.UTF8.GetString(rt.value);
            }

            member.SlotIdOrOffset             = mem.slotIdOrOffset;
            member.SlotLengthOrConceptGroupId = mem.slotLengthOrConceptGroup;

            member.Empty = member.RtxValue == null;
        }
        public virtual void UpdateMember(RegistryMemberBase member, RegMemElem17 mem, RegRtElem17 rt)
        {
#if DEBUG && !DEBUG_IN_PROD
            LogTo.Debug("[{0} {1}] Updating \"{member.Name}\"",
                        member.GetType().Name,
                        member.Id);
#endif

            if (mem.rtxOffset == 0)
            {
                member.Empty = true;

                return;
            }

            member.UseCount = mem.useCount;

            member.LinkType = (RegistryLinkType)mem.linkType;

            member.RtxOffset = mem.rtxOffset;
            member.RtxLength = mem.rtxLength;

            if (rt != null)
            {
                member.RtxId    = rt.no;
                member.RtxValue = Encoding.UTF8.GetString(rt.value);
            }

            member.SlotIdOrOffset             = mem.slotIdOrOffset;
            member.SlotLengthOrConceptGroupId = mem.slotLengthOrConceptGroup;
        }