예제 #1
0
        internal static async ValueTask DeleteViewRoute(string viewName, Transaction txn)
        {
            IntPtr keyPtr;
            int    keySize = EntityStoreWriter.CalcStringUtf8Size(viewName) + 1;

            unsafe
            {
                byte *pk = stackalloc byte[keySize];
                KeyUtil.WriteViewRouteKey(pk, viewName);
                keyPtr = new IntPtr(pk);
            }

            var req = new ClrDeleteRequire
            {
                RaftGroupId   = KeyUtil.META_RAFTGROUP_ID,
                KeyPtr        = keyPtr,
                KeySize       = new IntPtr(keySize),
                SchemaVersion = 0,
                ReturnExists  = false,
                DataCF        = -1
            };
            IntPtr reqPtr;

            unsafe { reqPtr = new IntPtr(&req); }
            await HostApi.ExecKVDeleteAsync(txn.Handle, reqPtr);
        }
예제 #2
0
        /// <summary>
        /// 根据分区键谓词计算扫描PartCF时KeySize
        /// </summary>
        private static unsafe int CalcPartitionKeySize(KeyPredicate?[] predicates, EntityModel model, int *varSizes)
        {
            int pkSize = 5;

            if (predicates != null)
            {
                for (int i = 0; i < predicates.Length; i++)
                {
                    if (!predicates[i].HasValue)
                    {
                        break;                          //没有指定谓词跳出
                    }
                    if (model.SysStoreOptions.PartitionKeys[i].Rule == PartitionKeyRule.None)
                    {
                        var m = predicates[i].Value.Value;
                        pkSize += EntityStoreWriter.CalcMemberSize(ref m, varSizes + i, true);
                    }
                    else
                    {
                        pkSize += 6; //暂统一2 + 4字节
                    }

                    if (predicates[i].Value.Type != KeyPredicateType.Equal) //非相等判断跳出
                    {
                        break;
                    }
                }
            }

            return(pkSize);
        }
예제 #3
0
        internal static unsafe void WriteViewRouteKey(byte *keyPtr, string viewName)
        {
            keyPtr[0] = METACF_VIEW_ROUTER_PREFIX;
            var writer = new EntityStoreWriter(keyPtr, 1);

            writer.WriteString(viewName, null);
        }
예제 #4
0
        /// <summary>
        /// 保存编译好的服务组件或视图运行时代码
        /// </summary>
        /// <param name="asmName">eg: sys.HelloService or sys.CustomerView</param>
        internal static ValueTask UpsertAssemblyAsync(bool isService, string asmName, byte[] asmData, Transaction txn)
        {
            IntPtr keyPtr;
            int    keySize = EntityStoreWriter.CalcStringUtf8Size(asmName) + 1;
            IntPtr dataPtr = IntPtr.Zero;

            unsafe
            {
                byte *pk = stackalloc byte[keySize];
                KeyUtil.WriteAssemblyKey(isService, pk, asmName);
                keyPtr = new IntPtr(pk);

                dataPtr = NativeApi.NewNativeString(asmData.Length, out byte *destDataPtr);
                fixed(byte *srcDataPtr = asmData)
                {
                    Buffer.MemoryCopy(srcDataPtr, destDataPtr, asmData.Length, asmData.Length);
                }
            }

            var req = new ClrInsertRequire
            {
                RaftGroupId      = KeyUtil.META_RAFTGROUP_ID,
                KeyPtr           = keyPtr,
                KeySize          = new IntPtr(keySize),
                DataPtr          = dataPtr,
                SchemaVersion    = 0,
                OverrideIfExists = true,
                DataCF           = -1
            };
            IntPtr reqPtr;

            unsafe { reqPtr = new IntPtr(&req); }
            return(HostApi.ExecKVInsertAsync(txn.Handle, reqPtr));
        }
예제 #5
0
        private static unsafe void WritePartitionKeyRange(KeyPredicate?[] predicates,
                                                          byte appId, EntityModel model,
                                                          byte *bk, byte *ek, int *varSizes)
        {
            var   tableId = model.TableId;
            byte *tiPtr   = (byte *)&tableId;

            bk[0] = ek[0] = appId;
            bk[1] = ek[1] = tiPtr[2];
            bk[2] = ek[2] = tiPtr[1];
            bk[3] = ek[3] = tiPtr[0];
            bk[4] = ek[4] = KeyUtil.PARTCF_PART_TABLE_FLAG;

            if (predicates == null || !predicates[0].HasValue) //short path for no predicate
            {
                ek[4] = KeyUtil.PARTCF_PART_TABLE_FLAG + 1;
                return;
            }

            var bw = new EntityStoreWriter(bk, 5);
            var ew = new EntityStoreWriter(ek, 5);

            for (int i = 0; i < predicates.Length; i++)
            {
                if (!predicates[i].HasValue)
                {
                    break;                          //没有指定谓词跳出
                }
                var m       = predicates[i].Value.Value;
                var ruleArg = model.SysStoreOptions.PartitionKeys[i].RuleArgument;

                switch (predicates[i].Value.Type)
                {
                case KeyPredicateType.Equal:
                {
                    if (model.SysStoreOptions.PartitionKeys[i].Rule == PartitionKeyRule.Hash)
                    {
                        int pkValue = EntityStoreWriter.GetHashOfPK(m.BoxedValue, ruleArg);
                        bw.WriteUInt16((ushort)(m.Id | 4));
                        bw.WriteInt32(pkValue);
                        ew.WriteUInt16((ushort)(m.Id | 4));
                        ew.WriteInt32(pkValue);
                    }
                    else if (model.SysStoreOptions.PartitionKeys[i].Rule == PartitionKeyRule.RangeOfDate)
                    {
                    }
                    else
                    {
                    }
                }
                break;

                default:
                    throw new NotImplementedException();
                }
            }
        }
예제 #6
0
        public async ValueTask <IndexRow> ToIndexRowAsync()
        {
            ValidatePredicates();

            var app = await RuntimeContext.Current.GetApplicationModelAsync(_indexModel.Owner.AppId);

            //Console.WriteLine($"IndexGet.ToIndexRowAsync: {StringHelper.ToHexString(keyPtr, keySize)}");
            //TODO:*****暂只支持非分区表索引
            if (_indexModel.Global || _indexModel.Owner.SysStoreOptions.HasPartitionKeys)
            {
                throw ExceptionHelper.NotImplemented();
            }

            //先获取目标分区
            ulong groupId = await EntityStore.GetOrCreateGlobalTablePartition(app, _indexModel.Owner, IntPtr.Zero);

            if (groupId == 0)
            {
                Log.Warn("Can't find index partition");
                return(IndexRow.Empty);
            }

            //生成Key
            IntPtr keyPtr;
            int    keySize = KeyUtil.INDEXCF_PREFIX_SIZE;

            unsafe
            {
                int *varSizes = stackalloc int[_indexModel.Fields.Length]; //主要用于记录String utf8数据长度,避免重复计算
                for (int i = 0; i < _indexModel.Fields.Length; i++)
                {
                    keySize += EntityStoreWriter.CalcMemberSize(ref _predicates[i].Value, varSizes + i, true);
                }

                byte *pkPtr = stackalloc byte[keySize];
                EntityId.WriteRaftGroupId(pkPtr, groupId);
                pkPtr[KeyUtil.INDEXCF_INDEXID_POS] = _indexModel.IndexId;

                var writer = new EntityStoreWriter(pkPtr, KeyUtil.INDEXCF_PREFIX_SIZE);
                for (int i = 0; i < _predicates.Length; i++)
                {
                    //注意写入索引键排序标记
                    writer.WriteMember(ref _predicates[i].Value, varSizes, true, _indexModel.Fields[i].OrderByDesc);
                }
                keyPtr = new IntPtr(pkPtr);
            }

            //TODO: 根据是否在事务内走ReadIndex或事务读命令
            var res = await StoreApi.Api.ReadIndexByGetAsync(groupId, keyPtr, (uint)keySize, KeyUtil.INDEXCF_INDEX);

            return(res == null ? IndexRow.Empty : new IndexRow(res));
        }
예제 #7
0
        private static ValueTask <INativeData> LoadAssemblyAsync(bool isService, string asmName)
        {
            IntPtr keyPtr;
            int    keySize = EntityStoreWriter.CalcStringUtf8Size(asmName) + 1;

            unsafe
            {
                byte *pk = stackalloc byte[keySize];
                KeyUtil.WriteAssemblyKey(isService, pk, asmName);
                keyPtr = new IntPtr(pk);
            }

            return(StoreApi.Api.ReadIndexByGetAsync(KeyUtil.META_RAFTGROUP_ID, keyPtr, (uint)keySize));
        }
예제 #8
0
        internal static unsafe void WriteAssemblyKey(bool isService, byte *keyPtr, string asmName)
        {
            if (isService)
            {
                keyPtr[0] = METACF_SERVICE_ASSEMBLY_PREFIX;
            }
            else
            {
                keyPtr[0] = METACF_VIEW_ASSEMBLY_PREFIX;
            }

            var writer = new EntityStoreWriter(keyPtr, 1);

            writer.WriteString(asmName, null);
        }
예제 #9
0
        /// <summary>
        /// 用于写入全部相等的分区Key
        /// </summary>
        private unsafe void WritePartitionKey(byte appId, EntityModel model, byte *key, int *varSizes)
        {
            var   tableId = model.TableId;
            byte *tiPtr   = (byte *)&tableId;

            key[0] = appId;
            key[1] = tiPtr[2];
            key[2] = tiPtr[1];
            key[3] = tiPtr[0];
            key[4] = KeyUtil.PARTCF_PART_TABLE_FLAG;

            var w = new EntityStoreWriter(key, 5);

            for (int i = 0; i < predicates.Length; i++)
            {
                Debug.Assert(predicates[i].Value.Type == KeyPredicateType.Equal);

                var m       = predicates[i].Value.Value;
                var ruleArg = model.SysStoreOptions.PartitionKeys[i].RuleArgument;

                if (model.SysStoreOptions.PartitionKeys[i].Rule == PartitionKeyRule.Hash)
                {
                    int pkValue = EntityStoreWriter.GetHashOfPK(m.BoxedValue, ruleArg);
                    w.WriteUInt16((ushort)(m.Id | 4)); //不用写排序标记
                    w.WriteInt32(pkValue);
                }
                else if (model.SysStoreOptions.PartitionKeys[i].Rule == PartitionKeyRule.RangeOfDate)
                {
                    int    pkValue = EntityStoreWriter.GetRangeOfPK(m.DateTimeValue, (DatePeriod)ruleArg);
                    ushort mid     = m.Id;
                    if (model.SysStoreOptions.PartitionKeys[i].OrderByDesc)
                    {
                        mid |= 1 << IdUtil.MEMBERID_ORDER_OFFSET;
                    }
                    w.WriteUInt16((ushort)(mid | 4)); //写入排序标记
                    w.WriteInt32(pkValue);
                }
                else
                {
                    w.WriteMember(ref m, varSizes + i, true, model.SysStoreOptions.PartitionKeys[i].OrderByDesc);
                }
            }
        }
예제 #10
0
        /// <summary>
        /// 将Entity转换为Value部分,返回非托管的内存指针
        /// </summary>
        /// <returns>主进程NativeString; 子进程NativeBytes</returns>
        internal unsafe static IntPtr WriteEntity(Entity entity, out int dataSize)
        {
            int *varSizes  = stackalloc int[entity.Members.Length]; //主要用于记录String utf8数据长度,避免重复计算
            int  totalSize = 0;

            for (int i = 0; i < entity.Members.Length; i++)
            {
                totalSize += CalcMemberSize(ref entity.Members[i], varSizes + i, false);
            }
            dataSize = totalSize;

            var w = new EntityStoreWriter(totalSize);

            for (int i = 0; i < entity.Members.Length; i++)
            {
                w.WriteMember(ref entity.Members[i], varSizes + i, false, false);
            }

            return(w.nativeStringPtr);
        }
예제 #11
0
        /// <summary>
        /// 写索引Value
        /// </summary>
        /// <returns>非惟一索引且没有覆盖字段返回IntPtr.Zero</returns>
        internal unsafe static IntPtr WriteIndexData(Entity entity, EntityIndexModel indexModel, out int dataSize)
        {
            if (!(indexModel.Unique || indexModel.HasStoringFields))
            {
                dataSize = 0;
                return(IntPtr.Zero);
            }

            int *varSizes  = null;
            int  totalSize = indexModel.Unique ? 2 + 16 : 0;

            if (indexModel.HasStoringFields)
            {
                int *vars = stackalloc int[indexModel.StoringFields.Length];
                for (int i = 0; i < indexModel.StoringFields.Length; i++)
                {
                    totalSize += CalcMemberSize(ref entity.GetMember(indexModel.StoringFields[i]), vars + i, true);
                }
                varSizes = vars;
            }
            dataSize = totalSize;

            var w = new EntityStoreWriter(totalSize);

            //先写入惟一索引指向的EntityId
            if (indexModel.Unique)
            {
                w.WriteUInt16(IdUtil.STORE_FIELD_ID_OF_ENTITY_ID);
                w.WriteGuid(entity.Id.Data);
            }
            //再写入StoringFields
            if (indexModel.HasStoringFields)
            {
                for (int i = 0; i < indexModel.StoringFields.Length; i++)
                {
                    w.WriteMember(ref entity.GetMember(indexModel.StoringFields[i]), varSizes + i, true, false); //TODO:考虑不写入Null
                }
            }

            return(w.nativeStringPtr);
        }
예제 #12
0
        internal unsafe static void WritePartitionKeys(Entity entity, EntityModel model, byte *pkPtr, int *varSizes)
        {
            var    w = new EntityStoreWriter(pkPtr, 5);
            ushort memberId;

            for (int i = 0; i < model.SysStoreOptions.PartitionKeys.Length; i++)
            {
                memberId = model.SysStoreOptions.PartitionKeys[i].MemberId;
                switch (model.SysStoreOptions.PartitionKeys[i].Rule)
                {
                case PartitionKeyRule.Hash:
                {
                    object fieldValue = memberId == 0 ? entity.CreateTimeUtc : entity.GetMember(memberId).BoxedValue;
                    int    pkValue    = GetHashOfPK(fieldValue, model.SysStoreOptions.PartitionKeys[i].RuleArgument);
                    w.WriteUInt16((ushort)(memberId | 4));         //不需要写入排序标记
                    w.WriteInt32(pkValue);
                }
                break;

                case PartitionKeyRule.RangeOfDate:
                {
                    DateTime fieldValue = memberId == 0 ? entity.CreateTimeUtc : entity.GetDateTime(memberId);
                    int      pkValue    = GetRangeOfPK(fieldValue, (DatePeriod)model.SysStoreOptions.PartitionKeys[i].RuleArgument);
                    if (model.SysStoreOptions.PartitionKeys[i].OrderByDesc)         //需要写入排序标记
                    {
                        memberId |= 1 << IdUtil.MEMBERID_ORDER_OFFSET;
                    }
                    w.WriteUInt16((ushort)(memberId | 4));
                    w.WriteInt32(pkValue);
                }
                break;

                default:
                    w.WriteMember(ref entity.GetMember(memberId), varSizes + i, true,    //TODO: check write null
                                  model.SysStoreOptions.PartitionKeys[i].OrderByDesc);
                    break;
                }
            }
        }
예제 #13
0
        internal unsafe void WriteKeyRange(ulong groupId, EntityIndexModel model,
                                           byte *bk, byte *ek, int *varSizes)
        {
            EntityId.WriteRaftGroupId(bk, groupId);
            EntityId.WriteRaftGroupId(ek, groupId);
            bk[KeyUtil.INDEXCF_INDEXID_POS] = ek[KeyUtil.INDEXCF_INDEXID_POS] = model.IndexId;

            if (predicates == null || !predicates[0].HasValue) //short path for no predicate
            {
                ek[KeyUtil.INDEXCF_INDEXID_POS] = (byte)(model.IndexId + 1);
                return;
            }

            var bw = new EntityStoreWriter(bk, KeyUtil.INDEXCF_PREFIX_SIZE);
            var ew = new EntityStoreWriter(ek, KeyUtil.INDEXCF_PREFIX_SIZE);

            for (int i = 0; i < predicates.Length; i++)
            {
                if (!predicates[i].HasValue)
                {
                    break;                          //没有指定谓词跳出
                }
                var m = predicates[i].Value.Value;

                switch (predicates[i].Value.Type)
                {
                case KeyPredicateType.Equal:
                {
                    //注意写入索引键的排序标记
                    bw.WriteMember(ref m, varSizes, true, model.Fields[i].OrderByDesc);
                    ew.WriteMember(ref m, varSizes, true, model.Fields[i].OrderByDesc);
                }
                break;

                default:
                    throw new NotImplementedException();
                }
            }
        }
예제 #14
0
        /// <summary>
        /// 保存视图模型路由表
        /// </summary>
        /// <param name="viewName">eg: sys.CustomerList</param>
        /// <param name="path">无自定义路由为空,有上级路由;分隔</param>
        internal static ValueTask UpsertViewRoute(string viewName, string path, Transaction txn)
        {
            //TODO:简化Key与Value编码,直接utf8,各减去3字节字符数标记
            IntPtr keyPtr;
            int    keySize   = EntityStoreWriter.CalcStringUtf8Size(viewName) + 1;
            IntPtr dataPtr   = IntPtr.Zero;
            int    valueSize = EntityStoreWriter.CalcStringUtf8Size(path);

            unsafe
            {
                byte *pk = stackalloc byte[keySize];
                KeyUtil.WriteViewRouteKey(pk, viewName);
                keyPtr = new IntPtr(pk);

                if (!string.IsNullOrEmpty(path))
                {
                    dataPtr = NativeApi.NewNativeString(valueSize, out byte *destDataPtr);
                    var sr = new EntityStoreWriter(destDataPtr, 0);
                    sr.WriteString(path, null);
                }
            }

            var req = new ClrInsertRequire
            {
                RaftGroupId      = KeyUtil.META_RAFTGROUP_ID,
                KeyPtr           = keyPtr,
                KeySize          = new IntPtr(keySize),
                DataPtr          = dataPtr,
                SchemaVersion    = 0,
                OverrideIfExists = true,
                DataCF           = -1
            };
            IntPtr reqPtr;

            unsafe { reqPtr = new IntPtr(&req); }
            return(HostApi.ExecKVInsertAsync(txn.Handle, reqPtr));
        }
예제 #15
0
        internal unsafe int CalcKeySize(int *varSizes)
        {
            int keySize = KeyUtil.INDEXCF_PREFIX_SIZE;

            if (predicates != null)
            {
                for (int i = 0; i < predicates.Length; i++)
                {
                    if (!predicates[i].HasValue)
                    {
                        break;                          //没有指定谓词跳出
                    }
                    var m = predicates[i].Value.Value;
                    keySize += EntityStoreWriter.CalcMemberSize(ref m, varSizes + i, true);

                    if (predicates[i].Value.Type != KeyPredicateType.Equal) //非相等判断跳出
                    {
                        break;
                    }
                }
            }

            return(keySize);
        }
예제 #16
0
        internal static async ValueTask UpdateModelAsync(ModelBase model, Transaction txn, Func <uint, ApplicationModel> getApp)
        {
            //TODO:考虑先处理变更项但不提议变更命令,再保存AcceptChanges后的模型数据,最后事务提议变更命令
            unchecked { model.Version += 1; } //注意:模型版本号+1

            IntPtr keyPtr;
            IntPtr dataPtr = SerializeModel(model, out int dataSize);

            unsafe
            {
                byte *pk = stackalloc byte[KeyUtil.MODEL_KEY_SIZE];
                KeyUtil.WriteModelKey(pk, model.Id);
                keyPtr = new IntPtr(pk);
            }
            var req = new ClrUpdateRequire()
            {
                RaftGroupId   = KeyUtil.META_RAFTGROUP_ID,
                KeyPtr        = keyPtr,
                KeySize       = new IntPtr(KeyUtil.MODEL_KEY_SIZE),
                DataPtr       = dataPtr,
                SchemaVersion = 0,
                DataCF        = -1,
                Merge         = false,
                ReturnExists  = false
            };
            IntPtr reqPtr;

            unsafe { reqPtr = new IntPtr(&req); }
            await HostApi.ExecKVUpdateAsync(txn.Handle, reqPtr);

            //EntityModel特殊处理
            if (model.ModelType == ModelType.Entity)
            {
                EntityModel em = (EntityModel)model;
                //system entity model's schema has changed
                if (em.SysStoreOptions != null && em.SysStoreOptions.OldSchemaVersion != em.SysStoreOptions.SchemaVersion)
                {
                    Log.Debug($"Entity[{em.Name}] schema changed, {em.SysStoreOptions.OldSchemaVersion} -> {em.SysStoreOptions.SchemaVersion}");
                    var app         = getApp(em.AppId);
                    var alterCmdPtr = NativeApi.NewAlterTable(em.TableId | ((uint)app.StoreId << 24), em.SysStoreOptions.SchemaVersion);
                    //开始处理成员变更项
                    foreach (var m in em.Members)
                    {
                        if (m.PersistentState == PersistentState.Detached && !m.AllowNull) //仅新的非空的成员
                        {
                            var defaultValue = new EntityMember();
                            if (m.Type == EntityMemberType.DataField) //TODO:other
                            {
                                defaultValue = ((DataFieldModel)m).DefaultValue.Value;
                            }

                            unsafe
                            {
                                int * varSizes  = stackalloc int[1];
                                var   valueSize = EntityStoreWriter.CalcMemberSize(ref defaultValue, varSizes, false);
                                byte *valueData = stackalloc byte[valueSize];
                                var   writer    = new EntityStoreWriter(valueData, 0);
                                writer.WriteMember(ref defaultValue, varSizes, false, false);

                                NativeApi.AlterTableAddColumn(alterCmdPtr, new IntPtr(valueData), valueSize);
                            }
                        }
                        else if (m.PersistentState == PersistentState.Deleted)
                        {
                            //TODO:考虑底层实现合并多个删除的成员
                            if (m.Type == EntityMemberType.DataField)
                            {
                                //TODO:引用外键特殊处理
                                NativeApi.AlterTableDropColumn(alterCmdPtr, m.MemberId);
                            }
                            else
                            {
                                throw ExceptionHelper.NotImplemented();
                            }
                        }
                    }

                    //开始处理索引变更项
                    if (em.SysStoreOptions.HasIndexes)
                    {
                        foreach (var index in em.SysStoreOptions.Indexes)
                        {
                            if (index.PersistentState == PersistentState.Detached)
                            {
                                IntPtr fieldsPtr   = IntPtr.Zero;
                                int    fieldsSize  = index.Fields.Length * 2;
                                IntPtr storingPtr  = IntPtr.Zero;
                                int    storingSize = index.HasStoringFields ? index.StoringFields.Length * 2 : 0;
                                unsafe
                                {
                                    byte *fPtr = stackalloc byte[fieldsSize];
                                    fieldsPtr = new IntPtr(fPtr);
                                    ushort *mPtr = (ushort *)fPtr;
                                    for (int i = 0; i < index.Fields.Length; i++)
                                    {
                                        //注意:传入底层的MemberId包含OrderFlag
                                        int orderFlag = index.Fields[i].OrderByDesc ? 1 : 0;
                                        mPtr[i] = (ushort)(index.Fields[i].MemberId | (orderFlag << IdUtil.MEMBERID_ORDER_OFFSET));
                                    }

                                    if (storingSize > 0)
                                    {
                                        byte *sPtr = stackalloc byte[storingSize];
                                        storingPtr = new IntPtr(sPtr);
                                        mPtr       = (ushort *)sPtr;
                                        for (int i = 0; i < index.StoringFields.Length; i++)
                                        {
                                            mPtr[i] = index.StoringFields[i];
                                        }
                                    }
                                }
                                NativeApi.AlterTableAddIndex(alterCmdPtr, index.IndexId, index.Global,
                                                             fieldsPtr, fieldsSize, storingPtr, storingSize);
                            }
                            else if (index.PersistentState == PersistentState.Deleted)
                            {
                                NativeApi.AlterTableDropIndex(alterCmdPtr, index.IndexId);
                            }
                        }
                    }

                    //递交AlterTable任务
                    await HostApi.ExecMetaAlterTableAsync(txn.Handle, alterCmdPtr);
                }
            }
        }