/// <summary> /// Adds a list of updates to the query result. The XML metadata is written to disk to avoid running out of memory /// </summary> /// <param name="overTheWireUpdates">The updates to add to the result</param> public void AddUpdates(IEnumerable <ServerSyncUpdateData> overTheWireUpdates) { foreach (var overTheWireUpdate in overTheWireUpdates) { var updateIdentity = new Identity(overTheWireUpdate.Id); bool newEntryToBeAdded = false; lock (Identities) { if (!Identities.Contains(updateIdentity)) { newEntryToBeAdded = true; } } if (newEntryToBeAdded) { // We need to parse the XML update blob string updateXml = overTheWireUpdate.XmlUpdateBlob; if (string.IsNullOrEmpty(updateXml)) { // If the plain text blob is not availabe, use the compressed XML blob if (overTheWireUpdate.XmlUpdateBlobCompressed == null || overTheWireUpdate.XmlUpdateBlobCompressed.Length == 0) { throw new Exception("Missing XmlUpdateBlobCompressed"); } // Note: This only works on Windows. updateXml = CabinetUtility.DecompressData(overTheWireUpdate.XmlUpdateBlobCompressed); } var xdoc = XDocument.Parse(updateXml, LoadOptions.None); var newUpdate = Update.FromUpdateXml(updateIdentity, xdoc); AddUpdate(newUpdate, updateXml, out var newUpdateIndex, xdoc); } } }
/// <summary> /// Adds an update to the query result. The XML metadata is written to disk to avoid running out of memory /// </summary> /// <param name="update">The updates to add to the result</param> /// <param name="updateMetadata">The update metadata to add</param> /// <param name="newUpdateIndex">The index of the new entry, if it was added to the index</param> /// <param name="updateXmlDoc">Update XML document used to load additional data if needed</param> /// <returns>True if a new entry was added, false otherwise</returns> private bool AddUpdate(Update update, string updateMetadata, out int newUpdateIndex, XDocument updateXmlDoc) { var updateIdentity = update.Identity; newUpdateIndex = 0; lock (Identities) { if (!Identities.Contains(updateIdentity)) { newUpdateIndex = AddUpdateEntry(update, updateXmlDoc); var updateEntryName = GetUpdateXmlPath(updateIdentity); OutputFile.PutNextEntry(new ZipEntry(updateEntryName)); OutputFile.Write(Encoding.UTF8.GetBytes(updateMetadata)); OutputFile.CloseEntry(); OutputFile.Flush(); return(true); } } return(false); }
private void AddUpdateBundleInformation(int newUpdateIndex, Identity newUpdateIdentity, XDocument updateXml) { var bundledUpdates = BundlesUpdatesParser.Parse(updateXml); if (PendingBundledUpdates.ContainsKey(newUpdateIdentity)) { // We've seen this update before, as bundled with other updates // Now that we have an update for it, adds its bundling information IsBundledTable.Add(newUpdateIndex, PendingBundledUpdates[newUpdateIdentity]); foreach (var newUpdateParentBundleIndex in PendingBundledUpdates[newUpdateIdentity]) { // A bundled update that was pending before was added; add it to the parent's list of bundled updates if (!BundlesIndex[newUpdateParentBundleIndex].Contains(newUpdateIndex)) { BundlesIndex[newUpdateParentBundleIndex].Add(newUpdateIndex); } } // Remove from list of pending updates; PendingBundledUpdates.Remove(newUpdateIdentity); } else { // When initially added, updates are not considered bundled // Updates become bundled when they are found within another update IsBundledTable.Add(newUpdateIndex, new List <int>()); } if (bundledUpdates.Count > 0) { var knownBundledUpdates = bundledUpdates.Where(u => Identities.Contains(u)).Select(id => this[id]); var unknownBundledUpdates = bundledUpdates.Where(u => !Identities.Contains(u)); // Add known bundled updates BundlesIndex.Add( newUpdateIndex, new List <int>(knownBundledUpdates)); // Mark all bundled updates as bundled foreach (var bundledUpdate in knownBundledUpdates) { // Try to mark the bundled update as bundled by adding it to the bundled table if (IsBundledTable.ContainsKey(bundledUpdate)) { // An entry already exists; switch it to true now, regardless of the previous value if (!IsBundledTable[bundledUpdate].Contains(newUpdateIndex)) { IsBundledTable[bundledUpdate].Add(newUpdateIndex); } } else { IsBundledTable.Add(bundledUpdate, new List <int>() { newUpdateIndex }); } } // Add unknown bundled updates to a pending list foreach (var bundledUpdate in unknownBundledUpdates) { // The bundled update was not added to the metadata collection yet. Put it on a pending list with a mapping to its parent bundle if (PendingBundledUpdates.ContainsKey(bundledUpdate)) { if (!PendingBundledUpdates[bundledUpdate].Contains(newUpdateIndex)) { PendingBundledUpdates[bundledUpdate].Add(newUpdateIndex); } } else { PendingBundledUpdates.TryAdd(bundledUpdate, new List <int>() { newUpdateIndex }); } } } }