/// <summary> /// Формирует значение кеша местоположения /// </summary> /// <param name="i">Идентификатор местоположения</param> /// <param name="buffer">Буфер</param> /// <returns></returns> private unsafe byte[] GetLocationJson(int i, JsonSerializer.Buffer buffer) { buffer.Reset(); LocationRecord rec = _db.GetLocationRecordById(i); JsonSerializer.WriteLocationRecord(buffer, rec); return(buffer.GetByteArray()); }
/// <summary> /// Собирает кеш городов /// </summary> private unsafe void AcquireCityCache() { // Сначала проходим по индексу городов и собираем интервалы, соответствующие одному городу List <IndexCacheItem> indexCache = new List <IndexCacheItem>(_db.RecordCount / 10); byte[] baCurrentCity = new byte[24]; fixed(byte *bpCurrentCity = &baCurrentCity[0]) { sbyte *currentCity = (sbyte *)bpCurrentCity; int startIndex = 0; for (int i = 0; i < _db.RecordCount; i++) { LocationRecord rec = _db.GetLocationRecordByNameIndex(i); if (i == 0 || Utils.CompareSbpCity(currentCity, rec.city, 24) != 0) { if (i > 0) { indexCache.Add(new IndexCacheItem(startIndex, i - 1)); startIndex = i; } Utils.CopyMemory(currentCity, rec.city, 24); } } indexCache.Add(new IndexCacheItem(startIndex, _db.RecordCount - 1)); } // Затем в параллельном режиме формируем записи в кеше для городов int indexCacheLength = indexCache.Count; int currentItemIndex = -1; Task[] tasks = new Task[_cacheLoadOperationsDop]; for (int i = 0; i < _cacheLoadOperationsDop; i++) { Task task = Task.Run(() => { while (true) { int cacheIndex = Interlocked.Increment(ref currentItemIndex); if (cacheIndex >= indexCacheLength) { return; } IndexCacheItem cacheItem = indexCache[cacheIndex]; LocationRecord rec = _db.GetLocationRecordByNameIndex(cacheItem.StartIndex); AddCityCacheEntry(new string(rec.city), cacheItem.StartIndex, cacheItem.EndIndex); } }); tasks[i] = task; } Task.WaitAll(tasks); }
internal static unsafe void WriteLocationRecord(Buffer buffer, LocationRecord rec) { buffer.Write(LocationCountryProperty); buffer.Write(_utf8.GetBytes(new string(rec.country))); buffer.Write(LocationRegionProperty); buffer.Write(_utf8.GetBytes(new string(rec.region))); buffer.Write(LocationPostalProperty); buffer.Write(_utf8.GetBytes(new string(rec.postal))); buffer.Write(LocationCityProperty); buffer.Write(_utf8.GetBytes(new string(rec.city))); buffer.Write(LocationOrganizationProperty); buffer.Write(_utf8.GetBytes(new string(rec.organization))); buffer.Write(LocationLatitudeProperty); buffer.Write(_utf8.GetBytes(rec.latitude.ToString(CultureInfo.InvariantCulture))); buffer.Write(LocationLongitudeProperty); buffer.Write(_utf8.GetBytes(rec.longitude.ToString(CultureInfo.InvariantCulture))); buffer.Write(_objectEnd); }
/// <summary> /// Осуществляет двоичный поиск города по сортированному индексу. /// Возвращает идентификатор первого найденного соответствия. /// </summary> /// <param name="city">Название города</param> /// <param name="rangeStart"> /// Принимает на вход идентификатор первого элемента интервала, в котором нужно осуществлять поиск. /// Возвращает идентификатор первого элемента интервала, в котором найден город /// </param> /// <param name="rangeEnd"> /// Принимает на вход идентификатор последнего элемента интервала, в котором нужно осуществлять поиск. /// Возвращает идентификатор последнего элемента интервала, в котором найден город /// </param> /// <returns>true, если город найден. Иначе false</returns> private unsafe int BinarySearchByCityName(sbyte *city, ref int rangeStart, ref int rangeEnd) { if (rangeStart > rangeEnd) { return(-1); } int rangeMiddle = (rangeStart + rangeEnd) / 2; bool elementFound = false; while (true) { LocationRecord rec = GetLocationRecordByNameIndex(rangeMiddle); int comparisonResult = Utils.CompareSbpCity(rec.city, city, 24); if (comparisonResult == 0) { elementFound = true; break; } if (rangeStart == rangeEnd) { break; } if (comparisonResult == 1) { rangeEnd = rangeMiddle - 1; } else { rangeStart = rangeMiddle + 1; } if (rangeEnd < rangeStart) { break; } rangeMiddle = (rangeStart + rangeEnd) / 2; } return(elementFound ? rangeMiddle : -1); }
/// <summary> /// Диагностический метод /// </summary> internal static unsafe void WriteDbFiles(DataHolder holder, int ipTableSize) { using (StreamWriter sw = new StreamWriter("ip.txt", false, Encoding.UTF8)) { for (int i = 0; i < ipTableSize; i++) { IpRecord rec = holder.IpTable[i]; LocationRecord lrec = holder.GetLocationRecordById((int)rec.location_index); string str = Utils.ConvertUintToIp(rec.ip_from).PadRight(20) + Utils.ConvertUintToIp(rec.ip_to).PadRight(20) + new string(lrec.city).PadRight(24); sw.WriteLine(str); } } using (StreamWriter sw = new StreamWriter("location.txt", false, Encoding.UTF8)) { for (int i = 0; i < holder.RecordCount; i++) { LocationRecord rec = holder.GetLocationRecordByNameIndex(i); string city = new string(rec.city); string country = new string(rec.country); string region = new string(rec.region); string postal = new string(rec.postal); string organization = new string(rec.organization); if (city.Length > 23 || country.Length > 7 || region.Length > 11 || postal.Length > 23 || organization.Length > 31) { throw new Exception(); } string str = city.PadRight(24) + country.PadRight(8) + region.PadRight(12) + postal.PadRight(12) + organization.PadRight(32) + rec.latitude.ToString().PadRight(20) + rec.longitude.ToString().PadRight(20); sw.WriteLine(str); } } }
/// <summary> /// Служебный метод /// </summary> internal unsafe string[] GetAllCities() { if (_isCacheAvailable) { return(new List <string>(_cityCache.Keys).ToArray()); } else { HashSet <string> set = new HashSet <string>(StringComparer.Ordinal); for (int i = 0; i < _db.RecordCount; i++) { LocationRecord rec = _db.GetLocationRecordById(i); string city = new string(rec.city); if (!set.Contains(city)) { set.Add(city); } } return(set.ToArray()); } }
/// <summary> /// Диагностический метод /// </summary> internal static unsafe void ReadCities(Database db) { int max = 0; Dictionary <string, int> dict = new Dictionary <string, int>(); for (int i = 0; i < db.RecordCount; i++) { LocationRecord rec = db.GetLocationRecordById(i); string strCity = new string(rec.city); int count; if (!dict.TryGetValue(strCity, out count)) { dict.Add(strCity, 1); max = Math.Max(1, max); } else { dict[strCity] = count + 1; max = Math.Max(count + 1, max); } } }