/// <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); }
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)); }
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); }
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); } } }