private unsafe void DropWriteAheadLogFile()
        {
            if (TrinityConfig.ReadOnly)
            {
                return;
            }

            if (m_logfile == null)
            {
                return;
            }

            Debug.Assert(m_logfile != null);
            Debug.Assert(m_logfile_path != null);

            Log.WriteLine(LogLevel.Info, "Dropping write-ahead-log file {0}", m_logfile_path);

            if (0 != CStdio.fclose(m_logfile))
            {
                Log.WriteLine(LogLevel.Error, "Failed to close the log file");
            }

            try
            {
                File.Delete(m_logfile_path);
            }
            catch (Exception ex)
            {
                Log.WriteLine(LogLevel.Error, "Failed to delete the log file: {0}", ex);
            }

            _update_write_ahead_log_file(null, null);
        }
        internal void _reset_write_ahead_log_status()
        {
            if (m_logfile != null)
            {
                CStdio.fclose(m_logfile);
            }

            _update_write_ahead_log_file(null, null);
        }
 private unsafe void CloseWriteAheadLogFile()
 {
     if (m_logfile == null)
     {
         return;
     }
     if (0 != CStdio.fclose(m_logfile))
     {
         Log.WriteLine(LogLevel.Error, "Failed to close the log file");
     }
 }
        private void LoadWriteAheadLogFile()
        {
            if (TrinityConfig.ReadOnly)
            {
                return;
            }

            string path = WriteAheadLogFilePath;

            Log.WriteLine(LogLevel.Info, "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.Info, "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.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.feof(new_fp))
                {
                    Log.WriteLine(LogLevel.Warning, "Found incompatible empty write-ahead-log file, ignoring.");
                    CStdio.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.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.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.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 ? true : SaveStorage())
            {
                /* Save storage succeded. 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.fclose(new_fp);
            }
            Environment.Exit(-1);
        }