MaxMind GeoIP Reader处理问题 - 在Reader.Dispose()之后的mmdb文件上发生UnauthorizedAccessException

时间:2014-08-18 08:14:39

标签: c# geoip maxmind

我正在使用MaxMind.Db.Reader类来访问GeoLite2-City.mmdb文件,并且我在读取器上调用dispose后对文件执行某些操作时遇到文件访问问题。

重现此问题的最简单方法是使用一个控制台应用程序,类似于MaxMind.Db.Benchmark项目,该项目有一个Reader类的静态实例,在我的例子中称为_cityReader。

现在,如果你将_cityReader变量设置为一个新的Reader实例,然后调用它上面的dispose(我也将它设置为null)然后移动文件(移动工作正常)然后调用文件上的删除' s在新位置,您将在删除操作中获得UnauthorizedAccessException ...

_cityReader = new Reader(@"C:\temp\MaxMind\Active\GeoLite2-City.mmdb", FileAccessMode.MemoryMapped);

_cityReader.Dispose();
_cityReader = null;

File.Move(@"C:\temp\MaxMind\Active\GeoLite2-City.mmdb", @"C:\temp\MaxMind\Active\GeoLite2-CityMoved.mmdb");
File.Delete(@"C:\temp\MaxMind\Active\GeoLite2-CityMoved.mmdb");

我发现如果我使用反射来调用Disc the _cityReader._stream.Value属性,那么在此方案中,在调用_cityReader变量本身上的dispose之前,该文件将删除...

_cityReader = new Reader(@"C:\temp\MaxMind\Active\GeoLite2-City.mmdb", FileAccessMode.MemoryMapped);

FieldInfo field = typeof(Reader).GetField("_stream", BindingFlags.NonPublic | BindingFlags.Instance);
ThreadLocal<Stream> fieldValue = (ThreadLocal<Stream>)field.GetValue(_cityReader);
fieldValue.Value.Dispose();

_cityReader.Dispose();
_cityReader = null;

File.Move(@"C:\temp\MaxMind\Active\GeoLite2-City.mmdb", @"C:\temp\MaxMind\Active\GeoLite2-CityMoved.mmdb");
File.Delete(@"C:\temp\MaxMind\Active\GeoLite2-CityMoved.mmdb");

但是,除此之外,我实际上将静态读取器对象放在与其创建的线程不同的线程上,并发现即使在该场景下使用反射做这一点也意味着我仍然得到UnauthorizedAccessException。在这种情况下,我发现在处理_cityReader变量并将其设置为null后,我需要强制执行垃圾收集。为了重现这个,我在控制台应用程序中有一个静态方法,就像这样......

private static void DisposeReaderAndSwitchFiles()
{
    _cityReader.Dispose();
    _cityReader = null;

    GC.Collect();

    //  Try switching files
    File.Move(@"C:\temp\MaxMind\Active\GeoLite2-City.mmdb", @"C:\temp\MaxMind\Active\GeoLite2-CityMoved.mmdb");
    File.Delete(@"C:\temp\MaxMind\Active\GeoLite2-CityMoved.mmdb");
}

然后在控制台应用程序的主要方法中我有这个......

_cityReader = new Reader(@"C:\temp\MaxMind\Active\GeoLite2-City.mmdb", FileAccessMode.MemoryMapped);

Thread t = new Thread(DisposeReaderAndSwitchFiles);
t.Start();
t.Join();

Console.WriteLine("Press Any Key To Continue...");
Console.ReadKey();

因此代码示例将起作用,但如果我从DisposeReaderAndSwitchFiles方法中删除GC.Collect()调用,则会收到UnauthorizedAccessException。

是否还有其他人遇到与MaxMind.Db.Reader对象类似的问题?

我做错了什么或我应该做的其他事情?感觉有点脏,迫使垃圾收集,如果可能的话我宁愿避免它。

谢谢,

菲尔

1 个答案:

答案 0 :(得分:0)

我遇到的问题并不完全相似,但仍然存在访问问题。你可以在这里找到它。 Exception while accessing maxmind's GeoIP-country.mmdb database through hive