Пример #1
0
        private static string GetTreeName(BlittableJsonReaderObject reduceEntry, IndexDefinitionBase indexDefinition, JsonOperationContext context)
        {
            HashSet <string> groupByFields;

            if (indexDefinition is MapReduceIndexDefinition)
            {
                groupByFields = ((MapReduceIndexDefinition)indexDefinition).GroupByFields;
            }
            else if (indexDefinition is AutoMapReduceIndexDefinition)
            {
                groupByFields = ((AutoMapReduceIndexDefinition)indexDefinition).GroupByFields.Keys.ToHashSet();
            }
            else
            {
                throw new InvalidOperationException("Invalid map reduce index definition: " + indexDefinition.GetType());
            }

            foreach (var prop in reduceEntry.GetPropertyNames())
            {
                if (groupByFields.Contains(prop))
                {
                    continue;
                }

                if (reduceEntry.Modifications == null)
                {
                    reduceEntry.Modifications = new DynamicJsonValue(reduceEntry);
                }

                reduceEntry.Modifications.Remove(prop);
            }

            var reduceKey = context.ReadObject(reduceEntry, "debug: creating reduce tree name");

            return(reduceKey.ToString());
        }
Пример #2
0
        private static DocumentCompareResult ComparePropertiesExceptStartingWithAt(BlittableJsonReaderObject current, BlittableJsonReaderObject modified,
                                                                                   bool isMetadata = false, bool tryMergeAttachmentsConflict = false)
        {
            var resolvedAttachmetConflict = false;

            var properties = new HashSet <string>(current.GetPropertyNames());

            foreach (var propertyName in modified.GetPropertyNames())
            {
                properties.Add(propertyName);
            }

            foreach (var property in properties)
            {
                if (property[0] == '@')
                {
                    if (isMetadata)
                    {
                        if (property.Equals(Constants.Documents.Metadata.Attachments, StringComparison.OrdinalIgnoreCase))
                        {
                            if (tryMergeAttachmentsConflict)
                            {
                                if (current.TryGetMember(property, out object _) == false ||
                                    modified.TryGetMember(property, out object _) == false)
                                {
                                    // Resolve when just 1 document have attachments
                                    resolvedAttachmetConflict = true;
                                    continue;
                                }

                                resolvedAttachmetConflict = ShouldResolveAttachmentsConflict(current, modified);
                                if (resolvedAttachmetConflict)
                                {
                                    continue;
                                }

                                return(DocumentCompareResult.NotEqual);
                            }
                        }
                        else if (property.Equals(Constants.Documents.Metadata.Collection, StringComparison.OrdinalIgnoreCase) == false)
                        {
                            continue;
                        }
                    }
                    else if (property.Equals(Constants.Documents.Metadata.Key, StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }
                }

                if (current.TryGetMember(property, out object currentProperty) == false ||
                    modified.TryGetMember(property, out object modifiedPropery) == false)
                {
                    return(DocumentCompareResult.NotEqual);
                }

                if (Equals(currentProperty, modifiedPropery) == false)
                {
                    return(DocumentCompareResult.NotEqual);
                }
            }

            return(DocumentCompareResult.Equal | (resolvedAttachmetConflict ? DocumentCompareResult.ShouldRecreateDocument : DocumentCompareResult.None));
        }
Пример #3
0
        private static unsafe bool CompareBlittable(string fieldPath, string id, BlittableJsonReaderObject originalBlittable,
                                                    BlittableJsonReaderObject newBlittable, IDictionary <string, DocumentsChanges[]> changes,
                                                    List <DocumentsChanges> docChanges)
        {
            BlittableJsonReaderObject.AssertNoModifications(originalBlittable, id, assertChildren: false);
            BlittableJsonReaderObject.AssertNoModifications(newBlittable, id, assertChildren: false);

            var newBlittableProps = newBlittable.GetPropertyNames();
            var oldBlittableProps = originalBlittable.GetPropertyNames();
            var newFields         = new HashSet <string>(newBlittableProps);

            newFields.ExceptWith(oldBlittableProps);
            var removedFields = new HashSet <string>(oldBlittableProps);

            removedFields.ExceptWith(newBlittableProps);

            using var orderedProperties = newBlittable.GetPropertiesByInsertionOrder();

            foreach (var field in removedFields)
            {
                if (changes == null)
                {
                    return(true);
                }
                if (field.Equals(LastModified) ||
                    field.Equals(ChangeVector) ||
                    field.Equals(Id))
                {
                    continue;
                }
                NewChange(fieldPath, field, null, null, docChanges, DocumentsChanges.ChangeType.RemovedField);
            }

            var newProp = new BlittableJsonReaderObject.PropertyDetails();
            var oldProp = new BlittableJsonReaderObject.PropertyDetails();

            for (int i = 0; i < orderedProperties.Size; i++)
            {
                newBlittable.GetPropertyByIndex(orderedProperties.Properties[i], ref newProp);

                if (newProp.Name.Equals(LastModified) ||
                    newProp.Name.Equals(Collection) ||
                    newProp.Name.Equals(ChangeVector) ||
                    newProp.Name.Equals(Id))
                {
                    continue;
                }

                if (newFields.Contains(newProp.Name))
                {
                    if (changes == null)
                    {
                        return(true);
                    }
                    NewChange(fieldPath, newProp.Name, newProp.Value, null, docChanges, DocumentsChanges.ChangeType.NewField);
                    continue;
                }

                var oldPropId = originalBlittable.GetPropertyIndex(newProp.Name);
                originalBlittable.GetPropertyByIndex(oldPropId, ref oldProp);

                switch ((newProp.Token & BlittableJsonReaderBase.TypesMask))
                {
                case BlittableJsonToken.Integer:
                case BlittableJsonToken.Boolean:
                case BlittableJsonToken.LazyNumber:
                case BlittableJsonToken.CompressedString:
                case BlittableJsonToken.String:
                    if (newProp.Value.Equals(oldProp.Value) || CompareValues(oldProp, newProp) ||
                        CompareStringsWithEscapePositions(newBlittable._context, oldProp, newProp))
                    {
                        break;
                    }
                    if (changes == null)
                    {
                        return(true);
                    }
                    NewChange(fieldPath, newProp.Name, newProp.Value, oldProp.Value, docChanges,
                              DocumentsChanges.ChangeType.FieldChanged);
                    break;

                case BlittableJsonToken.Null:
                    if (oldProp.Value == null)
                    {
                        break;
                    }
                    if (changes == null)
                    {
                        return(true);
                    }
                    NewChange(fieldPath, newProp.Name, null, oldProp.Value, docChanges,
                              DocumentsChanges.ChangeType.FieldChanged);
                    break;

                case BlittableJsonToken.StartArray:
                    var newArray = newProp.Value as BlittableJsonReaderArray;
                    var oldArray = oldProp.Value as BlittableJsonReaderArray;

                    if (newArray == null)
                    {
                        throw new InvalidDataException($"Invalid blittable, expected array but got {newProp.Value}");
                    }

                    if (oldArray == null)
                    {
                        if (changes == null)
                        {
                            return(true);
                        }

                        NewChange(fieldPath, newProp.Name, newProp.Value, oldProp.Value, docChanges,
                                  DocumentsChanges.ChangeType.FieldChanged);

                        break;
                    }

                    var changed = CompareBlittableArray(FieldPathCombine(fieldPath, newProp.Name), id, oldArray, newArray, changes, docChanges, newProp.Name);
                    if (changes == null && changed)
                    {
                        return(true);
                    }

                    break;

                case BlittableJsonToken.StartObject:
                    if (oldProp.Value == null ||
                        !(oldProp.Value is BlittableJsonReaderObject oldObj))
                    {
                        if (changes == null)
                        {
                            return(true);
                        }

                        NewChange(fieldPath, newProp.Name, newProp.Value, oldProp.Value, docChanges,
                                  DocumentsChanges.ChangeType.FieldChanged);
                        break;
                    }

                    if (!(newProp.Value is BlittableJsonReaderObject newObj))
                    {
                        throw new InvalidDataException($"Invalid blittable, expected object but got {newProp.Value}");
                    }

                    changed = CompareBlittable(FieldPathCombine(fieldPath, newProp.Name), id, oldObj, newObj, changes, docChanges);
                    if (changes == null && changed)
                    {
                        return(true);
                    }

                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            if ((changes == null) || (docChanges.Count <= 0))
            {
                return(false);
            }

            changes[id] = docChanges.ToArray();
            return(true);
        }
Пример #4
0
        private static bool TrySimplifyJson(BlittableJsonReaderObject document, Type rootType)
        {
            var simplified = false;

            foreach (var propertyName in document.GetPropertyNames())
            {
                var propertyType = GetPropertyType(propertyName, rootType);
                if (propertyType == typeof(JObject) || propertyType == typeof(JArray) || propertyType == typeof(JValue))
                {
                    // don't simplify the property if it's a JObject
                    continue;
                }

                var propertyValue = document[propertyName];

                if (propertyValue is BlittableJsonReaderArray propertyArray)
                {
                    simplified |= TrySimplifyJson(propertyArray, propertyType);
                    continue;
                }

                var propertyObject = propertyValue as BlittableJsonReaderObject;
                if (propertyObject == null)
                {
                    continue;
                }

                if (propertyObject.TryGet(Constants.Json.Fields.Type, out string type) == false)
                {
                    simplified |= TrySimplifyJson(propertyObject, propertyType);
                    continue;
                }

                if (ShouldSimplifyJsonBasedOnType(type) == false)
                {
                    continue;
                }

                simplified = true;

                if (document.Modifications == null)
                {
                    document.Modifications = new DynamicJsonValue(document);
                }

                if (propertyObject.TryGet(Constants.Json.Fields.Values, out BlittableJsonReaderArray values) == false)
                {
                    if (propertyObject.Modifications == null)
                    {
                        propertyObject.Modifications = new DynamicJsonValue(propertyObject);
                    }

                    propertyObject.Modifications.Remove(Constants.Json.Fields.Type);
                    continue;
                }

                document.Modifications[propertyName] = values;

                simplified |= TrySimplifyJson(values, propertyType);
            }

            return(simplified);
        }
Пример #5
0
        private static bool CompareBlittable(string id, BlittableJsonReaderObject originalBlittable,
                                             BlittableJsonReaderObject newBlittable, IDictionary <string, DocumentsChanges[]> changes,
                                             List <DocumentsChanges> docChanges)
        {
            BlittableJsonReaderObject.AssertNoModifications(originalBlittable, id, assertChildren: false);
            BlittableJsonReaderObject.AssertNoModifications(newBlittable, id, assertChildren: false);

            var newBlittableProps = newBlittable.GetPropertyNames();
            var oldBlittableProps = originalBlittable.GetPropertyNames();
            var newFields         = newBlittableProps.Except(oldBlittableProps);
            var removedFields     = oldBlittableProps.Except(newBlittableProps);

            var propertiesIds = newBlittable.GetPropertiesByInsertionOrder();

            foreach (var field in removedFields)
            {
                if (changes == null)
                {
                    return(true);
                }
                NewChange(field, null, null, docChanges, DocumentsChanges.ChangeType.RemovedField);
            }

            var newProp = new BlittableJsonReaderObject.PropertyDetails();
            var oldProp = new BlittableJsonReaderObject.PropertyDetails();

            foreach (var propId in propertiesIds)
            {
                newBlittable.GetPropertyByIndex(propId, ref newProp);

                if (newProp.Name.Equals(LastModified) ||
                    newProp.Name.Equals(Collection) ||
                    newProp.Name.Equals(ChangeVector) ||
                    newProp.Name.Equals(Id))
                {
                    continue;
                }

                if (newFields.Contains(newProp.Name))
                {
                    if (changes == null)
                    {
                        return(true);
                    }
                    NewChange(newProp.Name, newProp.Value, null, docChanges, DocumentsChanges.ChangeType.NewField);
                    continue;
                }

                var oldPropId = originalBlittable.GetPropertyIndex(newProp.Name);
                originalBlittable.GetPropertyByIndex(oldPropId, ref oldProp);

                switch ((newProp.Token & BlittableJsonReaderBase.TypesMask))
                {
                case BlittableJsonToken.Integer:
                case BlittableJsonToken.Boolean:
                case BlittableJsonToken.LazyNumber:
                case BlittableJsonToken.CompressedString:
                case BlittableJsonToken.String:
                    if (newProp.Value.Equals(oldProp.Value) || ComapreValues(oldProp, newProp))
                    {
                        break;
                    }
                    if (changes == null)
                    {
                        return(true);
                    }
                    NewChange(newProp.Name, newProp.Value, oldProp.Value, docChanges,
                              DocumentsChanges.ChangeType.FieldChanged);
                    break;

                case BlittableJsonToken.Null:
                    if (oldProp.Value == null)
                    {
                        break;
                    }
                    if (changes == null)
                    {
                        return(true);
                    }
                    NewChange(newProp.Name, null, oldProp.Value, docChanges,
                              DocumentsChanges.ChangeType.FieldChanged);
                    break;

                case BlittableJsonToken.StartArray:
                    var newArray = newProp.Value as BlittableJsonReaderArray;
                    var oldArray = oldProp.Value as BlittableJsonReaderArray;

                    if ((newArray == null) || (oldArray == null))
                    {
                        throw new InvalidDataException("Invalid blittable");
                    }

                    var changed = CompareBlittableArray(id, oldArray, newArray, changes, docChanges, newProp.Name);
                    if (changed == false)
                    {
                        break;
                    }

                    if (changes == null)
                    {
                        return(true);
                    }

                    break;

                case BlittableJsonToken.StartObject:
                    if (oldProp.Value == null)
                    {
                        if (changes == null)
                        {
                            return(true);
                        }

                        changed = true;
                        NewChange(newProp.Name, newProp.Value, null, docChanges,
                                  DocumentsChanges.ChangeType.FieldChanged);
                    }
                    else
                    {
                        changed = CompareBlittable(id, oldProp.Value as BlittableJsonReaderObject,
                                                   newProp.Value as BlittableJsonReaderObject, changes, docChanges);
                    }

                    if ((changes == null) && (changed))
                    {
                        return(true);
                    }

                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            if ((changes == null) || (docChanges.Count <= 0))
            {
                return(false);
            }

            changes[id] = docChanges.ToArray();
            return(true);
        }
Пример #6
0
        public override BlittableJsonReaderObject GetUpdatedValue(JsonOperationContext context, BlittableJsonReaderObject previousValue, long index)
        {
            if (string.IsNullOrWhiteSpace(Value.Name))
            {
                Value.Name = GenerateTaskName(previousValue);
            }

            var prevTaskId = Value.TaskId;

            Value.TaskId = index;

            string oldName = null;

            if (previousValue != null)
            {
                previousValue.Modifications ??= new DynamicJsonValue();

                if (previousValue.TryGet(Value.Name, out object _) == false)
                {
                    if (prevTaskId != 0)
                    {
                        foreach (var propertyName in previousValue.GetPropertyNames())
                        {
                            var property = (BlittableJsonReaderObject)previousValue[propertyName];
                            if (property.TryGet(nameof(ServerWideBackupConfiguration.TaskId), out long taskId) == false)
                            {
                                throw new RachisInvalidOperationException(
                                          $"Current {nameof(ServerWideBackupConfiguration)} has no {nameof(ServerWideBackupConfiguration.TaskId)} " +
                                          $"or the {nameof(ServerWideBackupConfiguration.TaskId)} is not of the correct type. " +
                                          $"Should not happen\n {previousValue}");
                            }

                            if (taskId != prevTaskId)
                            {
                                continue;
                            }

                            oldName = propertyName;
                            break;
                        }

                        if (oldName == null)
                        {
                            throw new RachisInvalidOperationException(
                                      $"Can't find {nameof(ServerWideBackupConfiguration)} with {nameof(ServerWideBackupConfiguration.Name)} {Value.Name} or with {nameof(ServerWideBackupConfiguration.TaskId)} {prevTaskId}. " +
                                      $"If you try to create new {nameof(ServerWideBackupConfiguration)} set the {nameof(ServerWideBackupConfiguration.TaskId)} to 0." +
                                      $"If you try to update exist {nameof(ServerWideBackupConfiguration)} and change its name, request the configuration again from the server to get the current {nameof(ServerWideBackupConfiguration.TaskId)} and send the {nameof(PutServerWideBackupConfigurationCommand)} again");
                        }
                    }
                }

                var modifications = new DynamicJsonValue(previousValue);
                if (oldName != null && oldName.Equals(Value.Name) == false)
                {
                    modifications.Remove(oldName);
                }

                modifications[Value.Name] = Value.ToJson();
                var blittableJsonReaderObject = context.ReadObject(previousValue, Name);
                return(blittableJsonReaderObject);
            }

            var djv = new DynamicJsonValue
            {
                [Value.Name] = Value.ToJson()
            };

            return(context.ReadObject(djv, Name));
        }