void CreateSecondaryKeyInfo(List <Tuple <int, IList <SecondaryKeyAttribute> > > attributes, Dictionary <uint, TableFieldInfo> primaryKeyFields, RelationVersionInfo prevVersion) { _secondaryKeys = new Dictionary <uint, SecondaryKeyInfo>(); _secondaryKeysNames = new Dictionary <string, uint>(); var skIndexNames = attributes.SelectMany(t => t.Item2).Select(a => a.Name).Distinct(); foreach (var indexName in skIndexNames) { var indexFields = new List <Tuple <int, SecondaryKeyAttribute> >(); //fieldIndex, attribute foreach (var kv in attributes) { var attr = kv.Item2.FirstOrDefault(a => a.Name == indexName); if (attr == null) { continue; } indexFields.Add(Tuple.Create(kv.Item1, attr)); } var orderedAttrs = indexFields.OrderBy(a => a.Item2.Order).ToList(); var info = new SecondaryKeyInfo { Name = indexName, Fields = new List <FieldId>(), Index = SelectSecondaryKeyIndex(indexName, prevVersion) }; var usedPKFields = new Dictionary <uint, object>(); foreach (var attr in orderedAttrs) { for (uint i = 1; i <= attr.Item2.IncludePrimaryKeyOrder; i++) { usedPKFields.Add(i, null); var pi = _primaryKeyFields.IndexOf(primaryKeyFields[i]); info.Fields.Add(new FieldId(true, (uint)pi)); } if (attr.Item1 < 0) { var pkOrder = (uint)-attr.Item1; usedPKFields.Add(pkOrder, null); var pi = _primaryKeyFields.IndexOf(primaryKeyFields[pkOrder]); info.Fields.Add(new FieldId(true, (uint)pi)); } else { info.Fields.Add(new FieldId(false, (uint)attr.Item1)); } } //fill all not present parts of primary key foreach (var pk in primaryKeyFields) { if (!usedPKFields.ContainsKey(pk.Key)) { info.Fields.Add(new FieldId(true, (uint)_primaryKeyFields.IndexOf(primaryKeyFields[pk.Key]))); } } _secondaryKeysNames[indexName] = info.Index; _secondaryKeys[info.Index] = info; } }
uint ReadRelationVersions(uint relationIndex, string name, Dictionary <uint, RelationVersionInfo> relationVersions) { uint lastPersistedVersion = 0; var relationInfoResolver = new RelationInfoResolver((ObjectDB)_tr.Owner); var writer = new SpanWriter(); writer.WriteByteArrayRaw(ObjectDB.RelationVersionsPrefix); writer.WriteVUInt32(relationIndex); var prefix = writer.GetSpan().ToArray(); if (!_trkv.FindFirstKey(prefix)) { return(lastPersistedVersion); } do { var keyReader = new SpanReader(_trkv.GetKey().Slice(prefix.Length)); var valueReader = new SpanReader(_trkv.GetValue()); lastPersistedVersion = keyReader.ReadVUInt32(); var relationVersionInfo = RelationVersionInfo.LoadUnresolved(ref valueReader, name); relationVersionInfo.ResolveFieldHandlers(relationInfoResolver.FieldHandlerFactory); relationVersions[lastPersistedVersion] = relationVersionInfo; } while (_trkv.FindNextKey(prefix)); return(lastPersistedVersion); }
uint ReadRelationVersions(uint relationIndex, string name, Dictionary <uint, RelationVersionInfo> relationVersions) { uint lastPersistedVersion = 0; { var relationInfoResolver = new RelationInfoResolver((ObjectDB)_tr.Owner); var writer = new ByteBufferWriter(); writer.WriteByteArrayRaw(ObjectDB.RelationVersionsPrefix); writer.WriteVUInt32(relationIndex); _trkv.SetKeyPrefix(writer.Data); if (!_trkv.FindFirstKey()) { return(lastPersistedVersion); } var keyReader = new KeyValueDBKeyReader(_trkv); var valueReader = new KeyValueDBValueReader(_trkv); do { keyReader.Restart(); valueReader.Restart(); lastPersistedVersion = keyReader.ReadVUInt32(); relationVersions[lastPersistedVersion] = RelationVersionInfo.Load(valueReader, relationInfoResolver.FieldHandlerFactory, name); } while (_trkv.FindNextKey()); } return(lastPersistedVersion); }
public RelationVersionInfo(Dictionary <uint, TableFieldInfo> primaryKeyFields, //order -> info List <Tuple <int, IList <SecondaryKeyAttribute> > > secondaryKeys, //positive: sec key field idx, negative: pk order, attrs TableFieldInfo[] secondaryKeyFields, TableFieldInfo[] fields, RelationVersionInfo prevVersion) { _primaryKeyFields = primaryKeyFields.OrderBy(kv => kv.Key).Select(kv => kv.Value).ToArray(); _secondaryKeyFields = secondaryKeyFields; CreateSecondaryKeyInfo(secondaryKeys, primaryKeyFields, prevVersion); _fields = fields; }
internal static bool Equal(RelationVersionInfo a, RelationVersionInfo b) { //PKs if (a._primaryKeyFields.Count != b._primaryKeyFields.Count) { return(false); } for (int i = 0; i < a._primaryKeyFields.Count; i++) { if (!TableFieldInfo.Equal(a._primaryKeyFields[i], b._primaryKeyFields[i])) { return(false); } } //SKs if (a._secondaryKeys.Count != b._secondaryKeys.Count) { return(false); } foreach (var key in a._secondaryKeys) { SecondaryKeyInfo bInfo; if (!b._secondaryKeys.TryGetValue(key.Key, out bInfo)) { return(false); } if (!SecondaryKeyInfo.Equal(key.Value, bInfo)) { return(false); } } //Fields if (a._fields.Length != b._fields.Length) { return(false); } for (int i = 0; i < a._fields.Length; i++) { if (!TableFieldInfo.Equal(a._fields[i], b._fields[i])) { return(false); } } return(true); }
static void CheckThatPrimaryKeyHasNotChanged(string name, RelationVersionInfo info, RelationVersionInfo previousInfo) { var pkFields = info.GetPrimaryKeyFields(); var prevPkFields = previousInfo.GetPrimaryKeyFields(); if (pkFields.Count != prevPkFields.Count) { throw new BTDBException($"Change of primary key in relation '{name}' is not allowed. Field count {pkFields.Count} != {prevPkFields.Count}."); } var en = pkFields.GetEnumerator(); var pen = prevPkFields.GetEnumerator(); while (en.MoveNext() && pen.MoveNext()) { if (!ArePrimaryKeyFieldsCompatible(en.Current.Handler, pen.Current.Handler)) { throw new BTDBException($"Change of primary key in relation '{name}' is not allowed. Field '{en.Current.Name}' is not compatible."); } } }
uint SelectSecondaryKeyIndex(string indexName, RelationVersionInfo prevVersion) { uint index = 1; if (prevVersion != null) { if (prevVersion._secondaryKeysNames.TryGetValue(indexName, out index)) { return(index); } index = 0; while (prevVersion._secondaryKeys.ContainsKey(index)) { index++; } } while (_secondaryKeys.ContainsKey(index)) { index++; } return(index); //use fresh one }
void UpdateSecondaryKeys(IInternalObjectDBTransaction tr, RelationVersionInfo info, RelationVersionInfo previousInfo) { foreach (var prevIdx in previousInfo.SecondaryKeys.Keys) { if (!info.SecondaryKeys.ContainsKey(prevIdx)) { DeleteSecondaryKey(tr.KeyValueDBTransaction, prevIdx); } } var secKeysToAdd = new List <KeyValuePair <uint, SecondaryKeyInfo> >(); foreach (var sk in info.SecondaryKeys) { if (!previousInfo.SecondaryKeys.ContainsKey(sk.Key)) { secKeysToAdd.Add(sk); } } if (secKeysToAdd.Count > 0) { CalculateSecondaryKey(tr, secKeysToAdd); } }
public RelationInfo(uint id, string name, IRelationInfoResolver relationInfoResolver, Type interfaceType, Type clientType, IInternalObjectDBTransaction tr) { _id = id; _name = name; _relationInfoResolver = relationInfoResolver; _interfaceType = interfaceType; _clientType = clientType; ClientRelationVersionInfo = CreateVersionInfoByReflection(); LoadVersionInfos(tr.KeyValueDBTransaction); ApartFields = FindApartFields(interfaceType, ClientRelationVersionInfo); if (LastPersistedVersion > 0 && RelationVersionInfo.Equal(_relationVersions[LastPersistedVersion], ClientRelationVersionInfo)) { _relationVersions[LastPersistedVersion] = ClientRelationVersionInfo; ClientTypeVersion = LastPersistedVersion; } else { ClientTypeVersion = LastPersistedVersion + 1; _relationVersions.Add(ClientTypeVersion, ClientRelationVersionInfo); var writerk = new ByteBufferWriter(); writerk.WriteByteArrayRaw(ObjectDB.RelationVersionsPrefix); writerk.WriteVUInt32(_id); writerk.WriteVUInt32(ClientTypeVersion); var writerv = new ByteBufferWriter(); ClientRelationVersionInfo.Save(writerv); tr.KeyValueDBTransaction.SetKeyPrefix(ByteBuffer.NewEmpty()); tr.KeyValueDBTransaction.CreateOrUpdateKeyValue(writerk.Data, writerv.Data); if (LastPersistedVersion > 0) { CheckThatPrimaryKeyHasNotChanged(name, ClientRelationVersionInfo, _relationVersions[LastPersistedVersion]); UpdateSecondaryKeys(tr, ClientRelationVersionInfo, _relationVersions[LastPersistedVersion]); } } _typeConvertorGenerator = tr.Owner.TypeConvertorGenerator; }
static bool AllKeyPrefixesAreSame(RelationVersionInfo relationInfo, ushort count) { foreach (var sk in relationInfo.SecondaryKeys) { var skFields = sk.Value; var idx = 0; foreach (var field in skFields.Fields) { if (!field.IsFromPrimaryKey) { return(false); } if (field.Index != idx) { return(false); } if (++idx == count) { break; } } } return(true); }