1

我正在设计一个 API。目前,我正在尝试安全地处理磁盘空间不足的情况。基本上,我们有一系列包含一些数据的文件。当磁盘满了,我们再去写一个数据文件的时候,当然会报错。此时,我们删除单个文件(从最旧到最新的文件列表循环,并在成功删除文件后重试)。然后,我们重试写入文件。重复该过程,直到文件写入没有错误。

现在有趣的部分。所有这些都是同时发生的。就像,在某些时候有 8 个线程同时执行此操作。这使事情变得更加有趣,并导致了一个奇怪的错误。

这是代码

    public void Save(string text, string id)
    {
        using (var store = IsolatedStorageFile.GetUserStoreForApplication())
        {
            var existing = store.GetFileNames(string.Format(Prefix + "/*-{0}.dat", id));
            if (existing.Any()) return; //it already is saved

            string name = string.Format(Prefix + "/{0}-{1}.dat", DateTime.UtcNow.ToString("yyyyMMddHHmmssfffffff"), id);
        tryagain:
            bool doover=false;
            try
            {
                AttemptFileWrite(store, name, text);
            }
            catch (IOException)
            {
                doover = true;
            }
            catch (IsolatedStorageException) //THIS LINE
            {
                doover = true;
            }
            if (doover)
            {
                Attempt(() => store.DeleteFile(name)); //because apparently this can also fail. 
                var files = store.GetFileNames(Path.Combine(Prefix, "*.dat"));
                foreach (var file in files.OrderBy(x=>x))
                {
                    try
                    {
                        store.DeleteFile(Path.Combine(Prefix, file));
                    }
                    catch
                    {
                        continue;
                    }
                    break;
                }
                goto tryagain; //prepare the velociraptor shield!
            }
        }
    }

    void AttemptFileWrite(IsolatedStorageFile store, string name, string text)
    {
        using (var file = store.OpenFile(
            name,
            FileMode.Create,
            FileAccess.ReadWrite,
            FileShare.None | FileShare.Delete
            ))
        {
            using (var writer = new StreamWriter(file))
            {
                writer.Write(text);
                writer.Flush();
                writer.Close();
            }
            file.Close();
        }
    }

    static void Attempt(Action func)
    {
        try
        {
            func();
        }
        catch
        {
        }
    }
    static T Attempt<T>(Func<T> func)
    {
        try
        {
            return func();
        }
        catch
        {
        }
        return default(T);
    }
    public string GetSaved()
    {

        string content=null;
        using (var store = IsolatedStorageFile.GetUserStoreForApplication())
        {
            var files = store.GetFileNames(Path.Combine(Prefix,"*.dat")).OrderBy(x => x);

            if (!files.Any()) return new MessageBatch();
            foreach (var filename in files)
            {
                IsolatedStorageFileStream file=null;
                try
                {
                    file = Attempt(() =>
                        store.OpenFile(Path.Combine(Prefix, filename), FileMode.Open, FileAccess.ReadWrite, FileShare.None | FileShare.Delete));
                    if (file == null)
                    {
                        continue; //couldn't open. assume locked or some such
                    }
                    file.Seek(0L, SeekOrigin.Begin);
                    using (var reader = new StreamReader(file))
                    {
                        content = reader.ReadToEnd();
                    }
                    //take note here. We delete the file, while we still have it open!
                    //This is done because having the file open prevents other readers, but if we close it first,
                    //then there is a race condition that right after closing the stream, another reader could pick it up and 
                    //open exclusively. It looks weird, but it's right. Trust me. 
                    store.DeleteFile(Path.Combine(Prefix, filename));
                    if (!string.IsNullOrEmpty(content))
                    {
                        break;
                    }
                }
                finally
                {
                    if (file != null) file.Close();
                }
            }
        }
        return content;
    }

在标有 THIS LINE 的那一行,就是我所说的。在执行 AttemptFileWrite 时,我可以查看store.AvailableSpace并看到有足够的空间将数据放入其中,但是在尝试打开文件时,它会抛出这个带有Operation Not Permitted. 除了这个奇怪的情况,在所有其他情况下,它只是抛出一个 IOException 并显示有关磁盘已满的消息

我想弄清楚我是否有一些奇怪的比赛条件,或者这是我必须处理的错误还是什么?

为什么会出现这个错误?

4

0 回答 0