Responsible to read a file which has a sequence of similar elements and pass a byte array of each element to a delgate for processing. Use low-level byte array methods, overlapping file read with parsing the file and calling the delegate. The expectation is that, after some unspecified header material, the file consists of a sequence of elements, all with the same tag (e.g., "rt" elements in FieldWorks XML backend). Following the last we expect a close tag for the containing element, e.g., "/languageProjet" in Fieldworks. These two tags can be configured so the class can be used in other ways. Enhance JohnT: Experiments on Websters indicate we're spending appreciable time on the parsing and calling the delegate. We could potentially do the parsing and delegate calling on different threads, perhaps even (since the order of calling delegates on different elements does not matter) split the parsing over multiple threads.
Inheritance: IDisposable
Esempio n. 1
0
		protected int ReadInSurrogates(int currentModelVersion)
		{
			for (; ; ) // Loop is used to retry if we get a corrupt file and restore backup.
			{
				var fileSize = new FileInfo(ProjectId.Path).Length;
				// This arbitrary length is based on two large databases, one 360M with 474 bytes/object, and one 180M with 541.
				// It's probably not perfect, but we're mainly trying to prevent fragmenting the large object heap
				// by growing it MANY times.
				var estimatedObjectCount = (int)(fileSize/400);
				m_identityMap.ExpectAdditionalObjects(estimatedObjectCount);

				if (!FileUtils.SimilarFileExists(ProjectId.Path))
					throw new InvalidOperationException("System does not exist.");

				try
				{
					// We need to reorder the entire file to be nice to Mercurial,
					// but only if the current version is less than "7000048".

					// Step 0: Get the version number.
					m_startupVersionNumber = GetActualModelVersionNumber(ProjectId.Path);
					var useLocalTempFile = !IsLocalDrive(ProjectId.Path);

					// Step 1:
					if (m_startupVersionNumber < 7000048)
					{
#if DEBUG
						var reorderWatch = new Stopwatch();
						reorderWatch.Start();
#endif
						var tempPathname = useLocalTempFile ? Path.GetTempFileName() : Path.ChangeExtension(ProjectId.Path, "tmp");
						// Rewrite the file in the prescribed order.
						using (var writer = FdoXmlServices.CreateWriter(tempPathname))
						{
							FdoXmlServices.WriteStartElement(writer, m_startupVersionNumber); // Use version from old file, so DM can be done, if needed.

							DataSortingService.SortEntireFile(m_mdcInternal.GetSortableProperties(), writer, ProjectId.Path);

							writer.WriteEndElement(); // 'languageproject'
							writer.Close();
						}

#if DEBUG
						reorderWatch.Stop();
						Debug.WriteLine("Reordering entire file took " + reorderWatch.ElapsedMilliseconds + " ms.");
						//Debug.Assert(false, "Force a stop.");
#endif
						// Copy reordered file to ProjectId.Path.
						CopyTempFileToOriginal(useLocalTempFile, ProjectId.Path, tempPathname);
					}

					// Step 2: Go on one's merry way....
					using (var reader = FdoXmlServices.CreateReader(ProjectId.Path))
					{
						reader.MoveToContent();
						m_needConversion = (m_startupVersionNumber != currentModelVersion);

						// Optional AdditionalFields element.
						if (reader.Read() && reader.LocalName == "AdditionalFields")
						{
							var cfiList = new List<CustomFieldInfo>();
							while (reader.Read() && reader.LocalName == "CustomField")
							{
								if (!reader.IsStartElement())
									continue;

								var cfi = new CustomFieldInfo();
								reader.MoveToAttribute("class");
								cfi.m_classname = reader.Value;
								if (reader.MoveToAttribute("destclass"))
									cfi.m_destinationClass = Int32.Parse(reader.Value);
								if (reader.MoveToAttribute("helpString"))
									cfi.m_fieldHelp = reader.Value;
								if (reader.MoveToAttribute("label"))
									cfi.Label = reader.Value;
								if (reader.MoveToAttribute("listRoot"))
									cfi.m_fieldListRoot = new Guid(reader.Value);
								reader.MoveToAttribute("name");
								cfi.m_fieldname = reader.Value;
								reader.MoveToAttribute("type");
								cfi.m_fieldType = GetFlidTypeFromString(reader.Value);
								if (reader.MoveToAttribute("wsSelector"))
									cfi.m_fieldWs = Int32.Parse(reader.Value);
								reader.MoveToElement();
								cfiList.Add(cfi);
							}
							RegisterOriginalCustomProperties(cfiList);
						}
					}

					Stopwatch watch = new Stopwatch();
					watch.Start();
					using (var er = new ElementReader("<rt ", "</languageproject>", ProjectId.Path, MakeSurrogate))
					{
						er.Run();
					}
					watch.Stop();
					Debug.WriteLine("Making surrogates took " + watch.ElapsedMilliseconds + " ms.");
				}
				catch (ArgumentException e)
				{
					Logger.WriteError(e);
					// Failed to get a version number from the file!
					OfferToRestore(Properties.Resources.kstidInvalidFieldWorksXMLFile);
					continue; // backup restored, if previous call returns.
				}
				catch (XmlException e)
				{
					Logger.WriteError(e);
					// The data is not in the format we expect or not even an XML file
					OfferToRestore(Properties.Resources.kstidInvalidFieldWorksXMLFile);
					continue; // backup restored, if previous call returns.
				}
				catch (IOException e)
				{
					Logger.WriteError(e);
					OfferToRestore(e.Message);
					continue; // backup restored, if previous call returns.
				}
				ReportDuplicateGuidsIfTheyExist();
				return m_startupVersionNumber;
			}
		}
		private void RunElementReaderWithSpecifiedBufferSize(string projPath, int bufferSize)
		{
			using (var er = new ElementReader("<rt ", kClosingTag, projPath, bytes => { }, bufferSize))
			{
				er.Run();
			}
		}