private void _LoadWriteAheadLogFile()

in src/Trinity.Core/Storage/LocalMemoryStorage/LocalMemoryStorage.WriteAheadLog.cs [352:521]


        private void _LoadWriteAheadLogFile()
        {
            lock (m_lock)
            {
                if (TrinityConfig.ReadOnly)
                    return;

                string path = _WriteAheadLogFilePath();

                Log.WriteLine(LogLevel.Debug, "Loading write-ahead log file {0}", path);

                LOG_FILE_HEADER         header              = LOG_FILE_HEADER.New();
                TRINITY_IMAGE_SIGNATURE current_sig         = new TRINITY_IMAGE_SIGNATURE();
                LOG_RECORD_HEADER       record_header       = new LOG_RECORD_HEADER();
                long                    record_cnt          = 0;
                byte[]                  cell_buff           = new byte[128];
                void*                   new_fp              = null;
                bool                    ver_compatible      = true;
                bool                    img_compatible      = true;

                GetTrinityImageSignature(&current_sig);

                _DropWriteAheadLogFile();

                if (!File.Exists(path))
                {
                    Log.WriteLine(LogLevel.Debug, "Write ahead log doesn't exist, quit loading.");
                    return;
                }

                if (0 != Stdio._wfopen_s(out new_fp, path, "rb"))
                {
                    Log.WriteLine(LogLevel.Fatal, "Cannot open write ahead log for read. Exiting.");
                    goto load_fail;
                }

                /* Read log header */

                if (1 != CStdio.C_fread(&header, (ulong)sizeof(LOG_FILE_HEADER), 1, new_fp))
                {
                    Log.WriteLine(LogLevel.Fatal, "Cannot read write-ahead-log header. Exiting.");
                    goto load_fail;
                }

                ver_compatible = header.CompatibilityCheck();
                img_compatible = Memory.Compare((byte*)&header.LOG_ASSOCIATED_IMAGE_SIGNATURE, (byte*)&current_sig, sizeof(TRINITY_IMAGE_SIGNATURE));

                if (!ver_compatible || !img_compatible)
                {
                    /* The log is not ours. Ignore if it's empty. */
                    if (0 == CStdio.C_feof(new_fp))
                    {
                        Log.WriteLine(LogLevel.Warning, "Found incompatible empty write-ahead-log file, ignoring.");
                        CStdio.C_fclose(new_fp);
                        return;
                    }
                    else if (this.CellCount != 0)
                    {
                        goto load_incompatible;
                    }
                    /* Otherwise, (CellCount is 0), it indicates that we're recovering from a fresh start. */
                }

                Log.WriteLine(LogLevel.Info, "Reading log file.");

                while (1 == CStdio.C_fread(&record_header, (ulong)sizeof(LOG_RECORD_HEADER), 1, new_fp))
                {
                    if (record_header.CONTENT_LEN >= 0)
                    {
                        /* Ensure space for the cell buffer */
                        if (record_header.CONTENT_LEN > cell_buff.Length)
                        {
                            if (record_header.CONTENT_LEN < 1<<20)
                            {
                                cell_buff = new byte[record_header.CONTENT_LEN * 2];
                            }
                            else
                            {
                                cell_buff = new byte[record_header.CONTENT_LEN];
                            }
                        }

                        fixed (byte* p_buff = cell_buff)
                        {
                            if (1 != CStdio.C_fread(p_buff, (ulong)record_header.CONTENT_LEN, 1, new_fp) && record_header.CONTENT_LEN != 0)
                            {
                                Log.WriteLine(LogLevel.Error, "Incomplete write-ahead-log record at the end of file");
                                break;
                            }

                            if (false == LOG_RECORD_HEADER.CWriteAheadLogValidateChecksum(&record_header, p_buff))
                            {
                                Log.WriteLine(LogLevel.Fatal, "Checksum mismatch for log record #{0}", record_cnt);
                                goto load_fail;
                            }

                            this.SaveCell(record_header.CELL_ID, p_buff, record_header.CONTENT_LEN, record_header.CELL_TYPE);
                        }
                    }
                    else /* if (record_header.CONTENT_LEN < 0) */
                    {
                        if (false == LOG_RECORD_HEADER.CWriteAheadLogValidateChecksum(&record_header, null))
                        {
                            Log.WriteLine(LogLevel.Fatal, "Checksum mismatch for log record #{0}", record_cnt);
                            goto load_fail;
                        }
                        this.RemoveCell(record_header.CELL_ID);
                    }

                    ++record_cnt;
                }

                goto load_success;

////////////////////////////////////////
load_incompatible:

                if (ver_compatible)
                {
                    Log.WriteLine(LogLevel.Fatal, "The log file is incompatible with the current version. Cannot recover.");
                }

                if (img_compatible)
                {
                    Log.WriteLine(LogLevel.Fatal, "The log file has a different signature than the current image. Cannot recover.");
                }

                goto load_fail;

////////////////////////////////////////
load_success:

                Log.WriteLine(LogLevel.Info, "Write-ahead-log successfully loaded. Recovered {0} records.", record_cnt);

                if (0 != CStdio.C_fclose(new_fp))
                {
                    Log.WriteLine(LogLevel.Error, "Cannot close the write-ahead-log file. Logging disabled.");
                    return;
                }

                /* Only save storage when the log is not empty. */
                if (record_cnt == 0 || TrinityErrorCode.E_SUCCESS == SaveStorage())
                {
                    /* Save storage succeeded. Dropping old logs now. */
                    try
                    {
                        File.Delete(path);
                    }
                    catch (Exception ex)
                    {
                        Log.WriteLine(LogLevel.Error, "Failed to delete the old logs: {0}", ex);
                    }
                }
                else
                {
                    /* Save storage failed. */
                    Log.WriteLine(LogLevel.Fatal, "Failed to save the recovered storage. The old log is retained");
                    goto load_fail;
                }

                return;

////////////////////////////////////////
load_fail:

                if (new_fp != null)
                    CStdio.C_fclose(new_fp);
                Environment.Exit(-1);
            }
        }