/// <summary> /// Creates a new GeonamesParser using the provided IDictionary to map each Cities' /// string TZ Name to int TimeZone ids. /// </summary> public GeonamesParser(DataTable featureCodesDataTable, GeonamesDirectoryInfo directory) { Directory = directory; _geonamesFiles = directory.ValidGeonamesFiles; FEATURECODE_FILE_PATH = Environment.CurrentDirectory + @"\Resources\geonames_feature_codes.txt"; _regex = new Regex(@"\t", RegexOptions.Compiled); _maxParallelism = Environment.ProcessorCount; // Assign a reusable buffer for each thread. _bufferPool = new ConcurrentPool <string[]>(_maxParallelism); // Allocate buffer pool. for (int i = 0; i < _maxParallelism; i++) { // Adding string[] with max number of City fields for size. _bufferPool.Push(new string[City.NUM_FIELDS]); } ParsedEntries = 0; if (null != featureCodesDataTable) { _featureCodesDataTable = featureCodesDataTable; } else { throw new ArgumentNullException("featureCodesDataTable"); } }
/// <summary> /// Instantiates and begins parsing the geonames and olson databases. /// </summary> public void BeginParsing() { RaiseParsingStarted(); ProgressText = "Verifying directories"; _olsonDirectoryInfo = new OlsonDirectoryInfo(Settings.Default.OlsonPath); bool isValidOlsonDir = _olsonDirectoryInfo.IsValid; _geonamesDirectoryInfo = new GeonamesDirectoryInfo(Settings.Default.GeonamesPath); bool isValidGeonamesDir = _geonamesDirectoryInfo.IsValid; if (!isValidOlsonDir && !isValidGeonamesDir) { // No need to lock, because only 1 thread accessing this. (UI Thread never accesses [Only creates it in app.xaml.cs]) App.ExceptionLogger.LogMedium(new InvalidDirectoryException("You must provide a valid Geonames directory, Olson directory, or both.")); RaiseParsingFinished(new ParsingFinishedEventArgs(ParsingResult.Failure)); return; } ProgressText = "Validating connection string"; using (SqlConnection conTest = new SqlConnection(ConnectionString)) { try { conTest.Open(); } catch (System.Exception e) { App.ExceptionLogger.LogMedium(e); RaiseParsingFinished(new ParsingFinishedEventArgs(ParsingResult.Failure)); return; } } _dbTools = new WorlTimeDatabaseTools(_conStrBuilder); TaskFactory f = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None); Task stage1 = f.StartNew(() => PopulateFiles(isValidGeonamesDir, isValidOlsonDir)); Task stage3 = null; Task stage4 = null; Task stage5 = null; if (isValidOlsonDir) { _olsonParser = new OlsonParser(_dbTools.GetTimeZoneDataTable(), _dbTools.GetRuleDataTable(), _dbTools.GetLeapDataTable(), _olsonDirectoryInfo); _olsonParser.FileParsing += OnParserFileParsing; _olsonParser.FileParsed += (s, e) => ProgressValue++; _timeZoneLookUpTable = _olsonParser.TimeZoneLookupTable; ProgressText = "Creating Olson database tables"; _dbTools.CreateOlsonDatabaseTables(); Task stage2 = f.StartNew( () => { ProgressText = "Parsing Olson database files"; _olsonParser.ReadTZDirectory(); }); Task.WaitAll(stage2); stage3 = f.StartNew( () => { ProgressText = "Uploading TimeZones"; BulkCopy(_olsonParser.TimeZones, false); ProgressText = "TimeZones successfully uploaded"; }); stage4 = f.StartNew( () => { ProgressText = "Uploading Rules"; BulkCopy(_olsonParser.Rules, false); ProgressText = "Rules successfully uploaded"; }); stage5 = f.StartNew( () => { ProgressText = "Uploading Leaps"; BulkCopy(_olsonParser.Leaps, false); ProgressText = "Leaps succesfully uploaded"; }); } Task stage6 = null; if (isValidGeonamesDir) { DataTable cityTable = _dbTools.GetCityDataTable(); _geonamesParser = new GeonamesParser(_dbTools.GetFeatureCodeDataTable(), _geonamesDirectoryInfo); stage6 = f.StartNew( () => { ProgressMaximum++; ProgressText = "Parsing geonames featurecodes file"; DataTable featureCodes = _geonamesParser.ReadFeatureCodesFile(); ProgressText = "Uploading geonames featurecodes file"; BulkCopy(featureCodes); }); _geonamesParser.EntryParsed += (s, e) => { object[] cityValues = e.DatabaseEntry; DataRow timeZone; string timeZoneName = (string)cityValues[19]; if (_timeZoneLookUpTable.TryGetValue(timeZoneName, out timeZone)) { cityValues[18] = timeZone[0]; lock (_cityTableLock) { cityTable.Rows.Add(cityValues); } } else { App.ExceptionLogger.LogLow(new System.Exception("Could not get the ID for the City: " + (string)cityValues[1] + " with TimeZoneName " + timeZoneName)); } }; _geonamesParser.FileParsing += OnParserFileParsing; System.Action <FileParseEventArgs> BatchParsed = (e) => { string name = e.ParsedFile.Name; ProgressText = "Uploading File " + name; lock (_cityTableLock) { BulkCopy(cityTable); cityTable.Rows.Clear(); } ProgressText = name + " successfully uploaded"; }; _geonamesParser.FileParsed += (s, e) => BatchParsed(e); ProgressText = "Creating Geonames database table"; _dbTools.CreateGeonamesDatabaseTables(); ProgressText = "Parsing Geonames city files"; _geonamesParser.ReadCityFiles(); } Task.WaitAll(stage1); if (isValidOlsonDir) { Task.WaitAll(stage3, stage4, stage5); } if (isValidGeonamesDir) { Task.WaitAll(stage6); } RaiseParsingFinished(new ParsingFinishedEventArgs(ParsingResult.Success)); }