示例#1
0
        private static List <List <PTable> > LoadPTables(StreamReader reader, string indexmapFilename, TFPos checkpoints)
        {
            var tables = new List <List <PTable> >();

            // all next lines are PTables sorted by levels
            string text;

            while ((text = reader.ReadLine()) != null)
            {
                if (checkpoints.PreparePosition < 0 || checkpoints.CommitPosition < 0)
                {
                    throw new CorruptIndexException(
                              string.Format("Negative prepare/commit checkpoint in non-empty IndexMap: {0}.", checkpoints));
                }

                PTable ptable = null;
                var    pieces = text.Split(',');
                try
                {
                    var level      = int.Parse(pieces[0]);
                    var position   = int.Parse(pieces[1]);
                    var file       = pieces[2];
                    var path       = Path.GetDirectoryName(indexmapFilename);
                    var ptablePath = Path.Combine(path, file);

                    ptable = PTable.FromFile(ptablePath);
                    ptable.VerifyFileHash();

                    CreateIfNeeded(level, tables);
                    tables[level].Insert(position, ptable);
                }
                catch (Exception exc)
                {
                    // if PTable file path was correct, but data is corrupted, we still need to dispose opened streams
                    if (ptable != null)
                    {
                        ptable.Dispose();
                    }

                    // also dispose all previously loaded correct PTables
                    for (int i = 0; i < tables.Count; ++i)
                    {
                        for (int j = 0; j < tables[i].Count; ++j)
                        {
                            tables[i][j].Dispose();
                        }
                    }

                    throw new CorruptIndexException("Error while loading IndexMap.", exc);
                }
            }
            return(tables);
        }
示例#2
0
        public static IndexMap FromFile(string filename, Func <IndexEntry, bool> isHashCollision, int maxTablesPerLevel = 4, bool loadPTables = true)
        {
            var  tables = new List <List <PTable> >();
            int  version;
            long prepareCheckpoint = -1;
            long commitCheckpoint  = -1;

            if (!File.Exists(filename))
            {
                return(new IndexMap(IndexMapVersion, tables, prepareCheckpoint, commitCheckpoint, isHashCollision, maxTablesPerLevel));
            }

            using (var f = File.OpenRead(filename))
                using (var reader = new StreamReader(f))
                {
                    // calculate real MD5 hash except first 32 bytes which are string representation of stored hash
                    f.Position = 32;
                    var realHash = MD5Hash.GetHashFor(f);
                    f.Position = 0;

                    // read stored MD5 hash and convert it from string to byte array
                    string text;
                    if ((text = reader.ReadLine()) == null)
                    {
                        throw new CorruptIndexException("IndexMap file is empty.");
                    }
                    if (text.Length != 32 || !text.All(x => char.IsDigit(x) || (x >= 'A' && x <= 'F')))
                    {
                        throw new CorruptIndexException("Corrupted MD5 hash.");
                    }

                    // check expected and real hashes are the same
                    var expectedHash = new byte[16];
                    for (int i = 0; i < 16; ++i)
                    {
                        expectedHash[i] = Convert.ToByte(text.Substring(i * 2, 2), 16);
                    }
                    if (expectedHash.Length != realHash.Length)
                    {
                        throw new InvalidOperationException("Invalid length of expected and real hash.");
                    }
                    for (int i = 0; i < realHash.Length; ++i)
                    {
                        if (expectedHash[i] != realHash[i])
                        {
                            throw new CorruptIndexException("Expected and real hash are different.");
                        }
                    }

                    // at this point we can assume the format is ok, so actually no need to check errors.

                    if ((text = reader.ReadLine()) == null)
                    {
                        throw new CorruptIndexException("Corrupted version.");
                    }
                    version = int.Parse(text);

                    // read and check prepare/commit checkpoint
                    if ((text = reader.ReadLine()) == null)
                    {
                        throw new CorruptIndexException("Corrupted commit checkpoint.");
                    }

                    try
                    {
                        var checkpoints = text.Split('/');
                        if (!long.TryParse(checkpoints[0], out prepareCheckpoint) || prepareCheckpoint < -1)
                        {
                            throw new CorruptIndexException("Invalid prepare checkpoint.");
                        }
                        if (!long.TryParse(checkpoints[1], out commitCheckpoint) || commitCheckpoint < -1)
                        {
                            throw new CorruptIndexException("Invalid commit checkpoint.");
                        }
                    }
                    catch (Exception exc)
                    {
                        throw new CorruptIndexException("Corrupted prepare/commit checkpoints pair.", exc);
                    }

                    // all next lines are PTables sorted by levels
                    while ((text = reader.ReadLine()) != null)
                    {
                        if (prepareCheckpoint < 0 || commitCheckpoint < 0)
                        {
                            throw new CorruptIndexException("Negative prepare/commit checkpoint in non-empty IndexMap.");
                        }

                        if (!loadPTables)
                        {
                            break;
                        }

                        PTable ptable = null;
                        var    pieces = text.Split(',');
                        try
                        {
                            var level      = int.Parse(pieces[0]);
                            var position   = int.Parse(pieces[1]);
                            var file       = pieces[2];
                            var path       = Path.GetDirectoryName(filename);
                            var ptablePath = Path.Combine(path, file);

                            ptable = PTable.FromFile(ptablePath);
                            ptable.VerifyFileHash();

                            CreateIfNeeded(level, tables);
                            tables[level].Insert(position, ptable);
                        }
                        catch (Exception exc)
                        {
                            // if PTable file path was correct, but data is corrupted, we still need to dispose opened streams
                            if (ptable != null)
                            {
                                ptable.Dispose();
                            }

                            // also dispose all previously loaded correct PTables
                            for (int i = 0; i < tables.Count; ++i)
                            {
                                for (int j = 0; j < tables[i].Count; ++j)
                                {
                                    tables[i][j].Dispose();
                                }
                            }

                            throw new CorruptIndexException("Error while loading IndexMap.", exc);
                        }
                    }
                }
            return(new IndexMap(version, tables, prepareCheckpoint, commitCheckpoint, isHashCollision, maxTablesPerLevel));
        }