Создание backup по сети

greg_123
Дата: 11.08.2012 12:06:57
Добрый день.

Хочу сделать в приложении резервное копирование бд (delphi, fierbird 2.1).
Ехе-файл и файл бд находятся на сервере, у пользователей выведены только ярлыки на ехе-шник.
Когда делаешь backup локально (из ехе-ника который лежит вместе с бд) - все работает.
Но когда пользователь (с клиентской машины, под sysdba) хочет сделать backup в локальную папку - backup не проходит.
(сеть одноранговая)

Можно ли организовать такой backup?

Кусок кода:
with dm.Backup do
    begin
      LoginPrompt:=false;
      BackUpFile.Clear;
      BackUpFile.Append(dirName+file_name_bd+'_'+tek_time+'.fbk');//локальный путь к файлу резервной копии
      DatabaseName := path_name;
      ServerName   := server_name;
      Protocol:=TCP;

      Params.Clear;
      Params.Add('user_name='+dm.DB.Params.Values['user_name']);
      Params.Add('password='+dm.DB.Params.Values['password']);

      Verbose:=true;
      try
        Active:=true;
        ServiceStart;

        RichEditBackUpProcess.Lines.Add('Начало процедуры резервного копирования бд.');
        while not Eof do RichEditBackUpProcess.Lines.Add(GetNextLine);
      except
        Active:=false;
        RichEditBackUpProcess.Lines.Add('Произошла ОШИБКА при выполнении резервного копирования бд! Дальнейшая работа невозможна!');
        exit;
      end;
      Active:=false;
      RichEditBackUpProcess.Lines.Add('Процедура резервного копирования бд завершена УСПЕШНО.');
    end;


Заранее спасибо.
Dimitry Sibiryakov
Дата: 11.08.2012 12:10:22

greg_123
Можно ли организовать такой backup?

Нельзя. Такое умеет только gbak.

Posted via ActualForum NNTP Server 1.5

hvlad
Дата: 11.08.2012 12:44:29
В 2.5.2 будет можно
Dimitry Sibiryakov
Дата: 11.08.2012 13:03:07

hvlad
В 2.5.2 будет можно

А не придётся для этого зашаривать папку клиентского компьютера и монтировать её на сервере?..

Posted via ActualForum NNTP Server 1.5

Симонов Денис
Дата: 11.08.2012 13:26:45
Нет. Не придётся.
CORE-2666

fbsvcmgr remotehost:service_mgr -user sysdba -password XXX \
action_backup -dbname some.fdb -bkp_file stdout >some.fbk


fbsvcmgr remotehost:service_mgr -user sysdba -password XXX \
action_restore -dbname some.fdb -bkp_file stdin <some.fbk
Alex Truhin
Дата: 15.08.2012 19:40:47
greg_123, можно запускать gbak перехватив IO, примерно так:
+

{$WARN SYMBOL_PLATFORM OFF}
procedure ExecuteFile(FileName : string; StdInput: RawByteString;
                      TimeOut: integer; aStdOutput, aErrOutput: TOutStr);
label
  Error;
type
  TPipeHandles = (IN_WRITE, IN_READ, OUT_WRITE, OUT_READ, ERR_WRITE, ERR_READ);
  TPipeArray = array[TPipeHandles] of THandle;
var
  i: cardinal;
  ph: TPipeHandles;
  sa: TSecurityAttributes;
  Pipes: TPipeArray;
  StartInf: TStartupInfo;
  ProcInf: TProcessInformation;
  Buf: array[0..1024] of AnsiChar;
  TimeStart: TDateTime;
  StdOutStr, ErrOutStr : RawByteString;

  procedure ReadOutput(aHnd : THandle; var aBufOut : RawByteString; aOutput: TOutStr);
  const TmpLen = 1000;
  var
    Idx : integer;
    TmpOut : RawByteString;
    BytesRead : cardinal;
  begin
    repeat
      SetLength(TmpOut, TmpLen);
      // Win32Check(
      ReadFile(aHnd, TmpOut[1], TmpLen - 1, BytesRead, nil);
      if BytesRead > 0 then begin
        SetLength(TmpOut, BytesRead);
        aBufOut := aBufOut + TmpOut;
        if AnsiStrings.AnsiPos(#13#10, TmpOut) > 0 then begin
          Idx := AnsiStrings.AnsiPos(#13#10, aBufOut);
          aStdOutput(copy(aBufOut, 1, Idx - 1));
          aBufOut := copy(aBufOut, Idx + 2, MaxInt);
        end;
      end;
    until BytesRead = 0;
  end;

begin
  StdOutStr := '';
  ProcInf.hProcess := INVALID_HANDLE_VALUE;
  for ph := Low(TPipeHandles) to High(TPipeHandles)
    do Pipes[ph] := INVALID_HANDLE_VALUE;
  // Создаем пайпы
  sa.nLength := sizeof(sa);
  sa.bInheritHandle := TRUE;
  sa.lpSecurityDescriptor := nil;
  try
    Win32Check(CreatePipe(Pipes[IN_READ], Pipes[IN_WRITE], @sa, 0));
    Win32Check(CreatePipe(Pipes[OUT_READ], Pipes[OUT_WRITE], @sa, 0));
    Win32Check(CreatePipe(Pipes[ERR_READ], Pipes[ERR_WRITE], @sa, 0));
    // Пишем StdIn
    StrPCopy(@Buf[0], stdInput + ^Z);
    Win32Check(WriteFile(Pipes[IN_WRITE], Buf, Length(stdInput), i, nil));
    // Хендл записи в StdIn надо закрыть - иначе выполняемая программа
    // может не прочитать или прочитать не весь StdIn.
    CloseHandle(Pipes[IN_WRITE]);
    Pipes[IN_WRITE] := INVALID_HANDLE_VALUE;
    // Структуры CreateProcess
    FillChar(StartInf, sizeof(TStartupInfo), 0);
    StartInf.cb := sizeof(TStartupInfo);
    StartInf.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
    StartInf.wShowWindow := SW_HIDE; // SW_SHOW; // SW_HIDE если надо запустить невидимо
    StartInf.hStdInput := Pipes[IN_READ];
    StartInf.hStdOutput := Pipes[OUT_WRITE];
    StartInf.hStdError  := Pipes[ERR_WRITE];
    Win32Check(CreateProcess(nil, PChar(FileName), nil, nil, True, NORMAL_PRIORITY_CLASS,
                             nil, nil, StartInf, ProcInf));
    // Хендл записи в StdOutput и StdError надо закрыть
    CloseHandle(Pipes[OUT_WRITE]);
    Pipes[OUT_WRITE] := INVALID_HANDLE_VALUE;
    CloseHandle(Pipes[ERR_WRITE]);
    Pipes[ERR_WRITE] := INVALID_HANDLE_VALUE;
    //
    TimeStart := Now;
    repeat
      i := WaitForSingleObject(ProcInf.hProcess, 100);
      // Если таймаут завершаем процесс
      if (Now - TimeStart) * SecsPerDay > TimeOut then begin
        // Пробуем завершить корректно
        CloseHandle(ProcInf.hThread);
        i := WaitForSingleObject(ProcInf.hProcess, 500);
        CloseHandle(ProcInf.hProcess);
        ProcInf.hProcess := INVALID_HANDLE_VALUE;
        // Если корректно не получилось - терминируем
        if i <> WAIT_OBJECT_0 then begin
          ProcInf.hProcess := OpenProcess(PROCESS_TERMINATE, FALSE, ProcInf.dwProcessId);
          if ProcInf.hProcess <> 0 then begin
            TerminateProcess(ProcInf.hProcess, 0);
            CloseHandle(ProcInf.hProcess);
            ProcInf.hProcess := INVALID_HANDLE_VALUE;
          end;
        end;
        raise ETimeOutException.Create('Process terminate on timeout');
      end;
      // Читаем StdOutput вывод
      ReadOutput(Pipes[OUT_READ], StdOutStr, aStdOutput);
      // Читаем StdError вывод
      ReadOutput(Pipes[ERR_READ], ErrOutStr, aErrOutput);
    until i = WAIT_OBJECT_0;
    //
    if StdOutStr <> ''
      then aStdOutput(StdOutStr);
    if ErrOutStr <> ''
      then aErrOutput(ErrOutStr);
  finally
    for ph := Low(TPipeHandles) to High(TPipeHandles) do
      if Pipes[ph] <> INVALID_HANDLE_VALUE
        then CloseHandle(Pipes[ph]);
    if ProcInf.hProcess <> INVALID_HANDLE_VALUE then begin
      CloseHandle(ProcInf.hProcess);
      CloseHandle(ProcInf.hThread);
    end;
  end;
end;
{$WARN SYMBOL_PLATFORM ON}

procedure TfrmDBArchive.btnRunBackupClick(Sender: TObject);
var CmdLine, OutS, ErrS : string;
begin
  if (edDBName.Text = '') or (edPassword.Text = '') then begin
    memLog.Lines.Add('Ошибка!');
    memLog.Lines.Add('Имя пользователя и пароль должны быть заданы!');
    exit;
  end;
  memLog.Lines.Clear;
 // c:\Firebird2.5\bin\gbak.exe -b localhost:arbat d:\arbat.fbk -user sysdba -pass 1
  CmdLine := edGBAKPath.Text + ' -b ' + MainAPI.DB.DBName + ' ' + edArchiveName.Text +
             ' -user ' + edDBName.Text + ' -pass ' + edPassword.Text;
  memLog.Lines.Add('Создание архива : ' + CmdLine);
  OutS := ''; ErrS := '';
  ExecuteFile(CmdLine, '', 1000,
    procedure(aStr : RawByteString)
    begin
      OutS := OutS + StringToWideString(aStr);
    end,
    procedure(aStr : RawByteString)
    begin
      ErrS := ErrS + StringToWideString(aStr);
    end
  );
  if ErrS <> '' then begin
    memLog.Lines.Add('Ошибка при выполнении бэкапа');
    memLog.Lines.Add(ErrS);
    memLog.Lines.Add(OutS);
  end else begin
    memLog.Lines.Add('Бэкап успешно создан!');
  end;
end;

kdv
Дата: 15.08.2012 20:22:35
люди, не надо фигней заниматься, тут все написано
http://www.ibase.ru/devinfo/gbak.htm
S.PR
Дата: 16.08.2012 01:13:49
Dimitry Sibiryakov
hvlad
В 2.5.2 будет можно

А не придётся для этого зашаривать папку клиентского компьютера и монтировать её на сервере?..

+1
на клиенте для записи с сервера доступ ёсць?
Симонов Денис
Дата: 16.08.2012 08:47:53
Нет.
Смотри мой ответ выше.