## 9 Appendix B: The Backup Call Back Interface

### 9.1 mnesia_backup callback behavior

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %%
    %% This module contains one implementation of callback functions
    %% used by Mnesia at backup and restore. The user may however
    %% write an own module the same interface as mnesia_backup and
    %% configure Mnesia so the alternate module performs the actual
    %% accesses to the backup media. This means that the user may put
    %% the backup on medias that Mnesia does not know about, possibly
    %% on hosts where Erlang is not running.
    %%
    %% The OpaqueData argument is never interpreted by other parts of
    %% Mnesia. It is the property of this module. Alternate implementations
    %% of this module may have different interpretations of OpaqueData.
    %% The OpaqueData argument given to open_write/1 and open_read/1
    %% are forwarded directly from the user.
    %%
    %% All functions must return {ok, NewOpaqueData} or {error, Reason}.
    %%
    %% The NewOpaqueData arguments returned by backup callback functions will
    %% be given as input when the next backup callback function is invoked.
    %% If any return value does not match {ok, _} the backup will be aborted.
    %%
    %% The NewOpaqueData arguments returned by restore callback functions will
    %% be given as input when the next restore callback function is invoked
    %% If any return value does not match {ok, _} the restore will be aborted.
    %%
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    -module(mnesia_backup).

    -include_lib("kernel/include/file.hrl").

    -export([
             %% Write access
             open_write/1,
             write/2,
             commit_write/1,
             abort_write/1,

             %% Read access
             open_read/1,
             read/1,
             close_read/1
            ]).

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %% Backup callback interface
    -record(backup, {tmp_file, file, file_desc}).

    %% Opens backup media for write
    %%
    %% Returns {ok, OpaqueData} or {error, Reason}
    open_write(OpaqueData) ->
        File = OpaqueData,
        Tmp = lists:concat([File,".BUPTMP"]),
        file:delete(Tmp),
        file:delete(File),
        case disk_log:open([{name, make_ref()},
                            {file, Tmp},
                            {repair, false},
                            {linkto, self()}]) of
            {ok, Fd} ->
                {ok, #backup{tmp_file = Tmp, file = File, file_desc = Fd}};
            {error, Reason} ->
                {error, Reason}
        end.

    %% Writes BackupItems to the backup media
    %%
    %% Returns {ok, OpaqueData} or {error, Reason}
    write(OpaqueData, BackupItems) ->
        B = OpaqueData,
        case disk_log:log_terms(B#backup.file_desc, BackupItems) of
            ok ->
                {ok, B};
            {error, Reason} ->
                abort_write(B),
                {error, Reason}
        end.

    %% Closes the backup media after a successful backup
    %%
    %% Returns {ok, ReturnValueToUser} or {error, Reason}
    commit_write(OpaqueData) ->
        B = OpaqueData,
        case disk_log:sync(B#backup.file_desc) of
            ok ->
                case disk_log:close(B#backup.file_desc) of
                    ok ->
                        case file:rename(B#backup.tmp_file, B#backup.file) of
                           ok ->
                                {ok, B#backup.file};
                           {error, Reason} ->
                                {error, Reason}
                        end;
                    {error, Reason} ->
                        {error, Reason}
                end;
            {error, Reason} ->
                {error, Reason}
        end.

    %% Closes the backup media after an interrupted backup
    %%
    %% Returns {ok, ReturnValueToUser} or {error, Reason}
    abort_write(BackupRef) ->
        Res = disk_log:close(BackupRef#backup.file_desc),
        file:delete(BackupRef#backup.tmp_file),
        case Res of
            ok ->
                {ok, BackupRef#backup.file};
            {error, Reason} ->
                {error, Reason}
        end.

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %% Restore callback interface

    -record(restore, {file, file_desc, cont}).

    %% Opens backup media for read
    %%
    %% Returns {ok, OpaqueData} or {error, Reason}
    open_read(OpaqueData) ->
        File = OpaqueData,
        case file:read_file_info(File) of
            {error, Reason} ->
                {error, Reason};
            _FileInfo -> %% file exists
                case disk_log:open([{file, File},
                                    {name, make_ref()},
                                    {repair, false},
                                    {mode, read_only},
                                    {linkto, self()}]) of
                    {ok, Fd} ->
                        {ok, #restore{file = File, file_desc = Fd, cont = start}};
                    {repaired, Fd, _, {badbytes, 0}} ->
                        {ok, #restore{file = File, file_desc = Fd, cont = start}};
                    {repaired, Fd, _, _} ->
                        {ok, #restore{file = File, file_desc = Fd, cont = start}};
                    {error, Reason} ->
                        {error, Reason}
                end
        end.

    %% Reads BackupItems from the backup media
    %%
    %% Returns {ok, OpaqueData, BackupItems} or {error, Reason}
    %%
    %% BackupItems == [] is interpreted as eof
    read(OpaqueData) ->
        R = OpaqueData,
        Fd = R#restore.file_desc,
        case disk_log:chunk(Fd, R#restore.cont) of
            {error, Reason} ->
                {error, {"Possibly truncated", Reason}};
            eof ->
                {ok, R, []};
            {Cont, []} ->
                read(R#restore{cont = Cont});
            {Cont, BackupItems, _BadBytes} ->
                {ok, R#restore{cont = Cont}, BackupItems};
            {Cont, BackupItems} ->
                {ok, R#restore{cont = Cont}, BackupItems}
        end.

    %% Closes the backup media after restore
    %%
    %% Returns {ok, ReturnValueToUser} or {error, Reason}
    close_read(OpaqueData) ->
        R = OpaqueData,
        case disk_log:close(R#restore.file_desc) of
            ok -> {ok, R#restore.file};
            {error, Reason} -> {error, Reason}
        end.

Copyright © 1991-2006 Ericsson AB