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