diff --git a/Makefile b/Makefile index 9880e5db..eb3e3ee2 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ OBJS = src/backup.o src/catalog.o src/configure.o src/data.o \ src/util.o src/validate.o src/datapagemap.o src/parsexlog.o \ src/xlogreader.o src/streamutil.o src/receivelog.o \ src/archive.o src/utils/parray.o src/utils/pgut.o src/utils/logger.o \ - src/utils/json.o + src/utils/json.o src/utils/thread.o EXTRA_CLEAN = src/datapagemap.c src/datapagemap.h src/xlogreader.c \ src/receivelog.c src/receivelog.h src/streamutil.c src/streamutil.h src/logging.h @@ -63,6 +63,7 @@ src/streamutil.c: $(top_srcdir)/src/bin/pg_basebackup/streamutil.c src/streamutil.h: $(top_srcdir)/src/bin/pg_basebackup/streamutil.h rm -f $@ && $(LN_S) $(srchome)/src/bin/pg_basebackup/streamutil.h $@ + ifeq ($(MAJORVERSION),10) src/walmethods.c: $(top_srcdir)/src/bin/pg_basebackup/walmethods.c rm -f $@ && $(LN_S) $(srchome)/src/bin/pg_basebackup/walmethods.c $@ diff --git a/doit.cmd b/doit.cmd new file mode 100644 index 00000000..cc29bc88 --- /dev/null +++ b/doit.cmd @@ -0,0 +1 @@ +perl win32build.pl "C:\Program Files\PostgresProEnterprise\10" "C:\projects\pgwininstall2\pgwininstall\builddir\postgresql\postgresql-10.3\src" \ No newline at end of file diff --git a/doit96.cmd b/doit96.cmd new file mode 100644 index 00000000..94d242c9 --- /dev/null +++ b/doit96.cmd @@ -0,0 +1 @@ +perl win32build96.pl "C:\PgPro96" "C:\PgProject\pg96ee\postgrespro\src" \ No newline at end of file diff --git a/msvs/pg_probackup.sln b/msvs/pg_probackup.sln new file mode 100644 index 00000000..2df4b404 --- /dev/null +++ b/msvs/pg_probackup.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2013 for Windows Desktop +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pg_probackup", "pg_probackup.vcxproj", "{4886B21A-D8CA-4A03-BADF-743B24C88327}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4886B21A-D8CA-4A03-BADF-743B24C88327}.Debug|Win32.ActiveCfg = Debug|Win32 + {4886B21A-D8CA-4A03-BADF-743B24C88327}.Debug|Win32.Build.0 = Debug|Win32 + {4886B21A-D8CA-4A03-BADF-743B24C88327}.Debug|x64.ActiveCfg = Debug|x64 + {4886B21A-D8CA-4A03-BADF-743B24C88327}.Debug|x64.Build.0 = Debug|x64 + {4886B21A-D8CA-4A03-BADF-743B24C88327}.Release|Win32.ActiveCfg = Release|Win32 + {4886B21A-D8CA-4A03-BADF-743B24C88327}.Release|Win32.Build.0 = Release|Win32 + {4886B21A-D8CA-4A03-BADF-743B24C88327}.Release|x64.ActiveCfg = Release|x64 + {4886B21A-D8CA-4A03-BADF-743B24C88327}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/msvs/template.pg_probackup.vcxproj b/msvs/template.pg_probackup.vcxproj new file mode 100644 index 00000000..044a3e73 --- /dev/null +++ b/msvs/template.pg_probackup.vcxproj @@ -0,0 +1,209 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {4886B21A-D8CA-4A03-BADF-743B24C88327} + Win32Proj + pg_probackup + + + + Application + true + v120 + MultiByte + + + Application + true + v120 + MultiByte + + + Application + false + v120 + true + MultiByte + + + Application + false + v120 + true + MultiByte + + + + + + + + + + + + + + + + + + + true + ../;@PGSRC@\include;@PGSRC@\bin\pg_basebackup;@PGSRC@\bin\pg_rewind;@PGSRC@\include\port\win32_msvc;@PGSRC@\interfaces\libpq;@PGSRC@\include\port\win32;@PGSRC@\port;@ADDINCLUDE@;@PGSRC@;$(IncludePath) + @PGROOT@\lib;$(LibraryPath) + + + + true + ../;@PGSRC@\include;@PGSRC@\bin\pg_basebackup;@PGSRC@\bin\pg_rewind;@PGSRC@\include\port\win32_msvc;@PGSRC@\interfaces\libpq;@PGSRC@\include\port\win32;@PGSRC@\port;@ADDINCLUDE@;@PGSRC@;$(IncludePath) + @PGROOT@\lib;$(LibraryPath) + + + + false + ../;@PGSRC@\include;@PGSRC@\bin\pg_basebackup;@PGSRC@\bin\pg_rewind;@PGSRC@\include\port\win32_msvc;@PGSRC@\interfaces\libpq;@PGSRC@\include\port\win32;@PGSRC@\port;@ADDINCLUDE@;@PGSRC@;$(IncludePath) + @PGROOT@\lib;$(LibraryPath) + + + + false + ../;@PGSRC@\include;@PGSRC@\bin\pg_basebackup;@PGSRC@\bin\pg_rewind;@PGSRC@\include\port\win32_msvc;@PGSRC@\interfaces\libpq;@PGSRC@\include\port\win32;@PGSRC@\port;@ADDINCLUDE@;@PGSRC@;$(IncludePath) + @PGROOT@\lib;$(LibraryPath) + + + + + + + Level3 + Disabled + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + @ADDLIBS32@;libpgfeutils.lib;libpgcommon.lib;libpgport.lib;libpq.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + Level3 + Disabled + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + @ADDLIBS@;libpgfeutils.lib;libpgcommon.lib;libpgport.lib;libpq.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + true + true + @ADDLIBS32@;libpgfeutils.lib;libpgcommon.lib;libpgport.lib;libpq.lib;ws2_32.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + libc;%(IgnoreSpecificDefaultLibraries) + + + + + Level3 + + + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + true + true + @ADDLIBS@;libpgfeutils.lib;libpgcommon.lib;libpgport.lib;libpq.lib;ws2_32.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + libc;%(IgnoreSpecificDefaultLibraries) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/msvs/template.pg_probackup96.vcxproj b/msvs/template.pg_probackup96.vcxproj new file mode 100644 index 00000000..c095d7cc --- /dev/null +++ b/msvs/template.pg_probackup96.vcxproj @@ -0,0 +1,207 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {4886B21A-D8CA-4A03-BADF-743B24C88327} + Win32Proj + pg_probackup + + + + Application + true + v120 + MultiByte + + + Application + true + v120 + MultiByte + + + Application + false + v120 + true + MultiByte + + + Application + false + v120 + true + MultiByte + + + + + + + + + + + + + + + + + + + true + ../;@PGSRC@\include;@PGSRC@\bin\pg_basebackup;@PGSRC@\bin\pg_rewind;@PGSRC@\include\port\win32_msvc;@PGSRC@\interfaces\libpq;@PGSRC@\include\port\win32;@PGSRC@\port;@ADDINCLUDE@;@PGSRC@;$(IncludePath) + @PGROOT@\lib;$(LibraryPath) + + + + true + ../;@PGSRC@\include;@PGSRC@\bin\pg_basebackup;@PGSRC@\bin\pg_rewind;@PGSRC@\include\port\win32_msvc;@PGSRC@\interfaces\libpq;@PGSRC@\include\port\win32;@PGSRC@\port;@ADDINCLUDE@;@PGSRC@;$(IncludePath) + @PGROOT@\lib;$(LibraryPath) + + + + false + ../;@PGSRC@\include;@PGSRC@\bin\pg_basebackup;@PGSRC@\bin\pg_rewind;@PGSRC@\include\port\win32_msvc;@PGSRC@\interfaces\libpq;@PGSRC@\include\port\win32;@PGSRC@\port;@ADDINCLUDE@;@PGSRC@;$(IncludePath) + @PGROOT@\lib;$(LibraryPath) + + + + false + ../;@PGSRC@\include;@PGSRC@\bin\pg_basebackup;@PGSRC@\bin\pg_rewind;@PGSRC@\include\port\win32_msvc;@PGSRC@\interfaces\libpq;@PGSRC@\include\port\win32;@PGSRC@\port;@ADDINCLUDE@;@PGSRC@;$(IncludePath) + @PGROOT@\lib;$(LibraryPath) + + + + + + + Level3 + Disabled + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + @ADDLIBS32@;libpgfeutils.lib;libpgcommon.lib;libpgport.lib;libpq.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + Level3 + Disabled + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + @ADDLIBS@;libpgfeutils.lib;libpgcommon.lib;libpgport.lib;libpq.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + true + true + @ADDLIBS32@;libpgfeutils.lib;libpgcommon.lib;libpgport.lib;libpq.lib;ws2_32.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + libc;%(IgnoreSpecificDefaultLibraries) + + + + + Level3 + + + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + true + true + @ADDLIBS@;libpgfeutils.lib;libpgcommon.lib;libpgport.lib;libpq.lib;ws2_32.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + libc;%(IgnoreSpecificDefaultLibraries) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/msvs/template.pg_probackup_2.vcxproj b/msvs/template.pg_probackup_2.vcxproj new file mode 100644 index 00000000..2fc101a4 --- /dev/null +++ b/msvs/template.pg_probackup_2.vcxproj @@ -0,0 +1,203 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {4886B21A-D8CA-4A03-BADF-743B24C88327} + Win32Proj + pg_probackup + + + + Application + true + v120 + MultiByte + + + Application + true + v120 + MultiByte + + + Application + false + v120 + true + MultiByte + + + Application + false + v120 + true + MultiByte + + + + + + + + + + + + + + + + + + + true + ../;@PGSRC@\include;@PGSRC@\bin\pg_basebackup;@PGSRC@\bin\pg_rewind;@PGSRC@\include\port\win32_msvc;@PGSRC@\interfaces\libpq;@PGSRC@\include\port\win32;@PGSRC@\port;@ADDINCLUDE@;$(IncludePath) + @PGROOT@\lib;@$(LibraryPath) + + + true + ../;@PGSRC@\include;@PGSRC@\bin\pg_basebackup;@PGSRC@\bin\pg_rewind;@PGSRC@\include\port\win32_msvc;@PGSRC@\interfaces\libpq;@PGSRC@\include\port\win32;@PGSRC@\port;@ADDINCLUDE@;$(IncludePath) + @PGROOT@\lib;@$(LibraryPath) + + + false + ../;@PGSRC@\include;@PGSRC@\bin\pg_basebackup;@PGSRC@\bin\pg_rewind;@PGSRC@\include\port\win32_msvc;@PGSRC@\interfaces\libpq;@PGSRC@\include\port\win32;@PGSRC@\port;@ADDINCLUDE@;$(IncludePath) + @PGROOT@\lib;@$(LibraryPath) + + + false + ../;@PGSRC@\include;@PGSRC@\bin\pg_basebackup;@PGSRC@\bin\pg_rewind;@PGSRC@\include\port\win32_msvc;@PGSRC@\interfaces\libpq;@PGSRC@\include\port\win32;@PGSRC@\port;@ADDINCLUDE@;$(IncludePath) + @PGROOT@\lib;@$(LibraryPath) + + + + + + Level3 + Disabled + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + @ADDLIBS@;libpgfeutils.lib;libpgcommon.lib;libpgport.lib;libpq.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + Level3 + Disabled + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + @ADDLIBS@;libpgfeutils.lib;libpgcommon.lib;libpgport.lib;libpq.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + true + true + @ADDLIBS@;libpgfeutils.lib;libpgcommon.lib;libpgport.lib;libpq.lib;ws2_32.lib;%(AdditionalDependencies) + libc;%(IgnoreSpecificDefaultLibraries) + + + + + Level3 + + + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + true + true + @ADDLIBS@;libpgfeutils.lib;libpgcommon.lib;libpgport.lib;libpq.lib;ws2_32.lib;%(AdditionalDependencies) + libc;%(IgnoreSpecificDefaultLibraries) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/backup.c b/src/backup.c index 5b4063fa..f24a0b0f 100644 --- a/src/backup.c +++ b/src/backup.c @@ -18,16 +18,16 @@ #include #include #include -#include -#include "libpq/pqsignal.h" -#include "storage/bufpage.h" #include "catalog/catalog.h" #include "catalog/pg_tablespace.h" #include "datapagemap.h" -#include "receivelog.h" -#include "streamutil.h" +#include "libpq/pqsignal.h" #include "pgtar.h" +#include "receivelog.h" +#include "storage/bufpage.h" +#include "streamutil.h" +#include "utils/thread.h" static int standby_message_timeout = 10 * 1000; /* 10 sec = default */ static XLogRecPtr stop_backup_lsn = InvalidXLogRecPtr; @@ -89,8 +89,8 @@ static bool pg_stop_backup_is_sent = false; static void backup_cleanup(bool fatal, void *userdata); static void backup_disconnect(bool fatal, void *userdata); -static void backup_files(void *arg); -static void remote_backup_files(void *arg); +static void *backup_files(void *arg); +static void *remote_backup_files(void *arg); static void do_backup_instance(void); @@ -253,7 +253,11 @@ ReceiveFileList(parray* files, PGconn *conn, PGresult *res, int rownum) else if (copybuf[156] == '2') { /* Symlink */ +#ifndef WIN32 pgfile->mode |= S_IFLNK; +#else + pgfile->mode |= S_IFDIR; +#endif } else elog(ERROR, "Unrecognized link indicator \"%c\"\n", @@ -289,7 +293,7 @@ remote_copy_file(PGconn *conn, pgFile* file) DATABASE_DIR); join_path_components(to_path, database_path, file->path); - out = fopen(to_path, "w"); + out = fopen(to_path, PG_BINARY_W); if (out == NULL) { int errno_tmp = errno; @@ -363,7 +367,7 @@ remote_copy_file(PGconn *conn, pgFile* file) * Take a remote backup of the PGDATA at a file level. * Copy all directories and files listed in backup_files_list. */ -static void +static void * remote_backup_files(void *arg) { int i; @@ -385,7 +389,7 @@ remote_backup_files(void *arg) if (S_ISDIR(file->mode)) continue; - if (__sync_lock_test_and_set(&file->lock, 1) != 0) + if (!pg_atomic_test_set_flag(&file->lock)) continue; file_backup_conn = pgut_connect_replication(pgut_dbname); @@ -441,6 +445,8 @@ remote_backup_files(void *arg) /* Data files transferring is successful */ arguments->ret = 0; + + return NULL; } /* @@ -456,8 +462,9 @@ do_backup_instance(void) char label[1024]; XLogRecPtr prev_backup_start_lsn = InvalidXLogRecPtr; - pthread_t backup_threads[num_threads]; - backup_files_args *backup_threads_args[num_threads]; + /* arrays with meta info for multi threaded backup */ + pthread_t *backup_threads; + backup_files_args *backup_threads_args; bool backup_isok = true; pgBackup *prev_backup = NULL; @@ -681,16 +688,19 @@ do_backup_instance(void) } /* setup threads */ - __sync_lock_release(&file->lock); + pg_atomic_clear_flag(&file->lock); } /* sort by size for load balancing */ parray_qsort(backup_files_list, pgFileCompareSize); /* init thread args with own file lists */ + backup_threads = (pthread_t *) palloc(sizeof(pthread_t)*num_threads); + backup_threads_args = (backup_files_args *) palloc(sizeof(backup_files_args)*num_threads); + for (i = 0; i < num_threads; i++) { - backup_files_args *arg = pg_malloc(sizeof(backup_files_args)); + backup_files_args *arg = &(backup_threads_args[i]); arg->from_root = pgdata; arg->to_root = database_path; @@ -701,33 +711,27 @@ do_backup_instance(void) arg->thread_cancel_conn = NULL; /* By default there are some error */ arg->ret = 1; - backup_threads_args[i] = arg; } /* Run threads */ elog(LOG, "Start transfering data files"); for (i = 0; i < num_threads; i++) { + backup_files_args *arg = &(backup_threads_args[i]); elog(VERBOSE, "Start thread num: %i", i); if (!is_remote_backup) - pthread_create(&backup_threads[i], NULL, - (void *(*)(void *)) backup_files, - backup_threads_args[i]); + pthread_create(&backup_threads[i], NULL, backup_files, arg); else - pthread_create(&backup_threads[i], NULL, - (void *(*)(void *)) remote_backup_files, - backup_threads_args[i]); + pthread_create(&backup_threads[i], NULL, remote_backup_files, arg); } - + /* Wait threads */ for (i = 0; i < num_threads; i++) { pthread_join(backup_threads[i], NULL); - if (backup_threads_args[i]->ret == 1) + if (backup_threads_args[i].ret == 1) backup_isok = false; - - pg_free(backup_threads_args[i]); } if (backup_isok) elog(LOG, "Data files are transfered"); @@ -1017,7 +1021,7 @@ check_system_identifiers(void) system_id_pgdata = get_system_identifier(pgdata); system_id_conn = get_remote_system_identifier(backup_conn); - + if (system_id_conn != system_identifier) elog(ERROR, "Backup data directory was initialized for system id %ld, but connected instance system id is %ld", system_identifier, system_id_conn); @@ -1040,14 +1044,15 @@ confirm_block_size(const char *name, int blcksz) res = pgut_execute(backup_conn, "SELECT pg_catalog.current_setting($1)", 1, &name); if (PQntuples(res) != 1 || PQnfields(res) != 1) elog(ERROR, "cannot get %s: %s", name, PQerrorMessage(backup_conn)); - + block_size = strtol(PQgetvalue(res, 0, 0), &endp, 10); - PQclear(res); - if ((endp && *endp) || block_size != blcksz) elog(ERROR, "%s(%d) is not compatible(%d expected)", name, block_size, blcksz); + + PQclear(res);//bad pointer to endp + } /* @@ -1802,7 +1807,7 @@ pg_stop_backup(pgBackup *backup) /* Write backup_label */ join_path_components(backup_label, path, PG_BACKUP_LABEL_FILE); - fp = fopen(backup_label, "w"); + fp = fopen(backup_label, PG_BINARY_W); if (fp == NULL) elog(ERROR, "can't open backup label file \"%s\": %s", backup_label, strerror(errno)); @@ -1850,7 +1855,7 @@ pg_stop_backup(pgBackup *backup) char tablespace_map[MAXPGPATH]; join_path_components(tablespace_map, path, PG_TABLESPACE_MAP_FILE); - fp = fopen(tablespace_map, "w"); + fp = fopen(tablespace_map, PG_BINARY_W); if (fp == NULL) elog(ERROR, "can't open tablespace map file \"%s\": %s", tablespace_map, strerror(errno)); @@ -2006,7 +2011,7 @@ backup_disconnect(bool fatal, void *userdata) * In incremental backup mode, copy only files or datafiles' pages changed after * previous backup. */ -static void +static void * backup_files(void *arg) { int i; @@ -2021,7 +2026,7 @@ backup_files(void *arg) pgFile *file = (pgFile *) parray_get(arguments->backup_files_list, i); elog(VERBOSE, "Copying file: \"%s\" ", file->path); - if (__sync_lock_test_and_set(&file->lock, 1) != 0) + if (!pg_atomic_test_set_flag(&file->lock)) continue; /* check for interrupt */ @@ -2126,6 +2131,8 @@ backup_files(void *arg) /* Data files transferring is successful */ arguments->ret = 0; + + return NULL; } /* diff --git a/src/catalog.c b/src/catalog.c index eb5d3be7..f19628c3 100644 --- a/src/catalog.c +++ b/src/catalog.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/src/configure.c b/src/configure.c index dc80981a..2fc27892 100644 --- a/src/configure.c +++ b/src/configure.c @@ -132,7 +132,8 @@ writeBackupCatalogConfig(FILE *out, pgBackupConfig *config) fprintf(out, "#Backup instance info\n"); fprintf(out, "PGDATA = %s\n", config->pgdata); - fprintf(out, "system-identifier = %li\n", config->system_identifier); + //fprintf(out, "system-identifier = %li\n", config->system_identifier); + fprintf(out, "system-identifier = %" INT64_MODIFIER "u\n", config->system_identifier); fprintf(out, "#Connection parameters:\n"); if (config->pgdatabase) diff --git a/src/data.c b/src/data.c index a1bdb91a..be07ce64 100644 --- a/src/data.c +++ b/src/data.c @@ -446,7 +446,7 @@ backup_data_file(backup_files_args* arguments, INIT_CRC32C(file->crc); /* open backup mode file for read */ - in = fopen(file->path, "r"); + in = fopen(file->path, PG_BINARY_R); if (in == NULL) { FIN_CRC32C(file->crc); @@ -480,7 +480,7 @@ backup_data_file(backup_files_args* arguments, /* open backup file for write */ join_path_components(to_path, to_root, file->path + strlen(from_root) + 1); - out = fopen(to_path, "w"); + out = fopen(to_path, PG_BINARY_W); if (out == NULL) { int errno_tmp = errno; @@ -569,18 +569,18 @@ restore_data_file(const char *from_root, pgFile *file, pgBackup *backup) { - char to_path[MAXPGPATH]; - FILE *in = NULL; - FILE *out = NULL; - BackupPageHeader header; - BlockNumber blknum; - size_t file_size; + char to_path[MAXPGPATH]; + FILE *in = NULL; + FILE *out = NULL; + BackupPageHeader header; + BlockNumber blknum; + size_t file_size; /* BYTES_INVALID allowed only in case of restoring file from DELTA backup */ if (file->write_size != BYTES_INVALID) { /* open backup mode file for read */ - in = fopen(file->path, "r"); + in = fopen(file->path, PG_BINARY_R); if (in == NULL) { elog(ERROR, "cannot open backup file \"%s\": %s", file->path, @@ -594,9 +594,9 @@ restore_data_file(const char *from_root, * re-open it with "w" to create an empty file. */ join_path_components(to_path, to_root, file->path + strlen(from_root) + 1); - out = fopen(to_path, "r+"); + out = fopen(to_path, PG_BINARY_R "+"); if (out == NULL && errno == ENOENT) - out = fopen(to_path, "w"); + out = fopen(to_path, PG_BINARY_W); if (out == NULL) { int errno_tmp = errno; @@ -690,13 +690,13 @@ restore_data_file(const char *from_root, } } - /* - * DELTA backup have no knowledge about truncated blocks as PAGE or PTRACK do - * But during DELTA backup we read every file in PGDATA and thus DELTA backup - * knows exact size of every file at the time of backup. - * So when restoring file from DELTA backup we, knowning it`s size at - * a time of a backup, can truncate file to this size. - */ + /* + * DELTA backup have no knowledge about truncated blocks as PAGE or PTRACK do + * But during DELTA backup we read every file in PGDATA and thus DELTA backup + * knows exact size of every file at the time of backup. + * So when restoring file from DELTA backup we, knowning it`s size at + * a time of a backup, can truncate file to this size. + */ if (backup->backup_mode == BACKUP_MODE_DIFF_DELTA) { @@ -759,7 +759,7 @@ copy_file(const char *from_root, const char *to_root, pgFile *file) file->write_size = 0; /* open backup mode file for read */ - in = fopen(file->path, "r"); + in = fopen(file->path, PG_BINARY_R); if (in == NULL) { FIN_CRC32C(crc); @@ -775,7 +775,7 @@ copy_file(const char *from_root, const char *to_root, pgFile *file) /* open backup file for write */ join_path_components(to_path, to_root, file->path + strlen(from_root) + 1); - out = fopen(to_path, "w"); + out = fopen(to_path, PG_BINARY_W); if (out == NULL) { int errno_tmp = errno; @@ -918,7 +918,7 @@ push_wal_file(const char *from_path, const char *to_path, bool is_compress, bool overwrite) { FILE *in = NULL; - FILE *out; + FILE *out=NULL; char buf[XLOG_BLCKSZ]; const char *to_path_p = to_path; char to_path_temp[MAXPGPATH]; @@ -930,7 +930,7 @@ push_wal_file(const char *from_path, const char *to_path, bool is_compress, #endif /* open file for read */ - in = fopen(from_path, "r"); + in = fopen(from_path, PG_BINARY_R); if (in == NULL) elog(ERROR, "Cannot open source WAL file \"%s\": %s", from_path, strerror(errno)); @@ -946,7 +946,7 @@ push_wal_file(const char *from_path, const char *to_path, bool is_compress, snprintf(to_path_temp, sizeof(to_path_temp), "%s.partial", gz_to_path); - gz_out = gzopen(to_path_temp, "wb"); + gz_out = gzopen(to_path_temp, PG_BINARY_W); if (gzsetparams(gz_out, compress_level, Z_DEFAULT_STRATEGY) != Z_OK) elog(ERROR, "Cannot set compression level %d to file \"%s\": %s", compress_level, to_path_temp, get_gz_error(gz_out, errno)); @@ -961,7 +961,7 @@ push_wal_file(const char *from_path, const char *to_path, bool is_compress, snprintf(to_path_temp, sizeof(to_path_temp), "%s.partial", to_path); - out = fopen(to_path_temp, "w"); + out = fopen(to_path_temp, PG_BINARY_W); if (out == NULL) elog(ERROR, "Cannot open destination WAL file \"%s\": %s", to_path_temp, strerror(errno)); @@ -1083,7 +1083,7 @@ get_wal_file(const char *from_path, const char *to_path) #endif /* open file for read */ - in = fopen(from_path, "r"); + in = fopen(from_path, PG_BINARY_R); if (in == NULL) { #ifdef HAVE_LIBZ @@ -1092,7 +1092,7 @@ get_wal_file(const char *from_path, const char *to_path) * extension. */ snprintf(gz_from_path, sizeof(gz_from_path), "%s.gz", from_path); - gz_in = gzopen(gz_from_path, "rb"); + gz_in = gzopen(gz_from_path, PG_BINARY_R); if (gz_in == NULL) { if (errno == ENOENT) @@ -1120,7 +1120,7 @@ get_wal_file(const char *from_path, const char *to_path) /* open backup file for write */ snprintf(to_path_temp, sizeof(to_path_temp), "%s.partial", to_path); - out = fopen(to_path_temp, "w"); + out = fopen(to_path_temp, PG_BINARY_W); if (out == NULL) elog(ERROR, "Cannot open destination WAL file \"%s\": %s", to_path_temp, strerror(errno)); @@ -1254,7 +1254,7 @@ calc_file_checksum(pgFile *file) file->write_size = 0; /* open backup mode file for read */ - in = fopen(file->path, "r"); + in = fopen(file->path, PG_BINARY_R); if (in == NULL) { FIN_CRC32C(crc); diff --git a/src/dir.c b/src/dir.c index 8df3da3f..20725f88 100644 --- a/src/dir.c +++ b/src/dir.c @@ -10,7 +10,6 @@ #include "pg_probackup.h" -#include #include #include #include @@ -102,10 +101,12 @@ int dir_create_dir(const char *dir, mode_t mode) { char copy[MAXPGPATH]; - char parent[MAXPGPATH]; + char *parent; strncpy(copy, dir, MAXPGPATH); - strncpy(parent, dirname(copy), MAXPGPATH); + + parent = pstrdup(dir); + get_parent_directory(parent); /* Create parent first */ if (access(parent, F_OK) == -1) @@ -119,6 +120,7 @@ dir_create_dir(const char *dir, mode_t mode) elog(ERROR, "cannot create directory \"%s\": %s", dir, strerror(errno)); } + pfree(parent); return 0; } @@ -153,6 +155,8 @@ pgFileInit(const char *path) file = (pgFile *) pgut_malloc(sizeof(pgFile)); + file->name = 0; + file->size = 0; file->mode = 0; file->read_size = 0; @@ -232,7 +236,7 @@ pgFileGetCRC(pgFile *file) int errno_tmp; /* open file in binary read mode */ - fp = fopen(file->path, "r"); + fp = fopen(file->path, PG_BINARY_R); if (fp == NULL) elog(ERROR, "cannot open file \"%s\": %s", file->path, strerror(errno)); @@ -350,7 +354,7 @@ dir_list_file(parray *files, const char *root, bool exclude, bool omit_symlink, char black_item[MAXPGPATH * 2]; black_list = parray_new(); - black_list_file = fopen(path, "r"); + black_list_file = fopen(path, PG_BINARY_R); if (black_list_file == NULL) elog(ERROR, "cannot open black_list: %s", strerror(errno)); @@ -827,7 +831,11 @@ print_file_list(FILE *out, const parray *files, const char *root) if (file->is_datafile) fprintf(out, ",\"segno\":\"%d\"", file->segno); +#ifndef WIN32 if (S_ISLNK(file->mode)) +#else + if (pgwin32_is_junction(file->path)) +#endif fprintf(out, ",\"linked\":\"%s\"", file->linked); if (file->n_blocks != -1) diff --git a/src/pg_probackup.c b/src/pg_probackup.c index efb8e6a3..c66179e1 100644 --- a/src/pg_probackup.c +++ b/src/pg_probackup.c @@ -10,6 +10,7 @@ #include "pg_probackup.h" #include "streamutil.h" +#include "utils/thread.h" #include #include @@ -207,11 +208,7 @@ main(int argc, char *argv[]) /* * Save main thread's tid. It is used call exit() in case of errors. */ -#ifdef WIN32 - main_tid = GetCurrentThreadId(); -#else main_tid = pthread_self(); -#endif /* Parse subcommands and non-subcommand options */ if (argc > 1) @@ -235,7 +232,7 @@ main(int argc, char *argv[]) else if (strcmp(argv[1], "show") == 0) backup_subcmd = SHOW; else if (strcmp(argv[1], "delete") == 0) - backup_subcmd = DELETE; + backup_subcmd = DELETE_SUBCMD; else if (strcmp(argv[1], "set-config") == 0) backup_subcmd = SET_CONFIG; else if (strcmp(argv[1], "show-config") == 0) @@ -281,7 +278,7 @@ main(int argc, char *argv[]) if (backup_subcmd == BACKUP || backup_subcmd == RESTORE || backup_subcmd == VALIDATE || - backup_subcmd == DELETE) + backup_subcmd == DELETE_SUBCMD) { int i, len = 0, @@ -325,6 +322,7 @@ main(int argc, char *argv[]) if (backup_path == NULL) elog(ERROR, "required parameter not specified: BACKUP_PATH (-B, --backup-path)"); } + canonicalize_path(backup_path); /* Ensure that backup_path is an absolute path */ if (!is_absolute_path(backup_path)) @@ -402,7 +400,7 @@ main(int argc, char *argv[]) { if (backup_subcmd != RESTORE && backup_subcmd != VALIDATE - && backup_subcmd != DELETE + && backup_subcmd != DELETE_SUBCMD && backup_subcmd != SHOW) elog(ERROR, "Cannot use -i (--backup-id) option together with the '%s' command", argv[1]); @@ -464,6 +462,7 @@ main(int argc, char *argv[]) start_time = time(NULL); backup_mode = deparse_backup_mode(current.backup_mode); + current.stream = stream_wal; elog(INFO, "Backup start, pg_probackup version: %s, backup ID: %s, backup mode: %s, instance: %s, stream: %s, remote: %s", PROGRAM_VERSION, base36enc(start_time), backup_mode, instance_name, @@ -484,7 +483,7 @@ main(int argc, char *argv[]) false); case SHOW: return do_show(current.backup_id); - case DELETE: + case DELETE_SUBCMD: if (delete_expired && backup_id_string_param) elog(ERROR, "You cannot specify --delete-expired and --backup-id options together"); if (!delete_expired && !delete_wal && !backup_id_string_param) diff --git a/src/pg_probackup.h b/src/pg_probackup.h index d3ce8241..8face84d 100644 --- a/src/pg_probackup.h +++ b/src/pg_probackup.h @@ -15,10 +15,6 @@ #include #include -#ifndef WIN32 -#include -#endif - #include "access/timeline.h" #include "access/xlogdefs.h" #include "access/xlog_internal.h" @@ -28,6 +24,13 @@ #include "storage/checksum.h" #include "utils/pg_crc.h" #include "common/relpath.h" +#include "port.h" + +#ifdef FRONTEND +#undef FRONTEND + #include "port/atomics.h" +#define FRONTEND +#endif #include "utils/parray.h" #include "utils/pgut.h" @@ -102,7 +105,7 @@ typedef struct pgFile bool is_database; bool exists_in_prev; /* Mark files, both data and regular, that exists in previous backup */ CompressAlg compress_alg; /* compression algorithm applied to the file */ - volatile uint32 lock; /* lock for synchronization of parallel threads */ + volatile pg_atomic_flag lock; /* lock for synchronization of parallel threads */ datapagemap_t pagemap; /* bitmap of pages updated since previous backup */ } pgFile; @@ -144,7 +147,7 @@ typedef enum ProbackupSubcmd RESTORE, VALIDATE, SHOW, - DELETE, + DELETE_SUBCMD, SET_CONFIG, SHOW_CONFIG } ProbackupSubcmd; @@ -531,4 +534,16 @@ extern void pgBackup_init(pgBackup *backup); /* in status.c */ extern bool is_pg_running(void); +#ifdef WIN32 +#ifdef _DEBUG +#define lseek _lseek +#define open _open +#define fstat _fstat +#define read _read +#define close _close +#define write _write +#define mkdir(dir,mode) _mkdir(dir) +#endif +#endif + #endif /* PG_PROBACKUP_H */ diff --git a/src/restore.c b/src/restore.c index 69bac841..0e42c4c4 100644 --- a/src/restore.c +++ b/src/restore.c @@ -14,14 +14,14 @@ #include #include #include -#include #include "catalog/pg_control.h" +#include "utils/thread.h" typedef struct { - parray *files; - pgBackup *backup; + parray *files; + pgBackup *backup; /* * Return value from the thread. @@ -65,7 +65,7 @@ static void check_tablespace_mapping(pgBackup *backup); static void create_recovery_conf(time_t backup_id, pgRecoveryTarget *rt, pgBackup *backup); -static void restore_files(void *arg); +static void *restore_files(void *arg); static void remove_deleted_files(pgBackup *backup); static const char *get_tablespace_mapping(const char *dir); static void set_tablespace_created(const char *link, const char *dir); @@ -80,13 +80,11 @@ static TablespaceCreatedList tablespace_created_dirs = {NULL, NULL}; * Entry point of pg_probackup RESTORE and VALIDATE subcommands. */ int -do_restore_or_validate(time_t target_backup_id, - pgRecoveryTarget *rt, - bool is_restore) +do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt, + bool is_restore) { int i; parray *backups; - parray *timelines; pgBackup *current_backup = NULL; pgBackup *dest_backup = NULL; pgBackup *base_full_backup = NULL; @@ -169,6 +167,8 @@ do_restore_or_validate(time_t target_backup_id, if (rt->recovery_target_tli) { + parray *timelines; + elog(LOG, "target timeline ID = %u", rt->recovery_target_tli); /* Read timeline history files from archives */ timelines = readTimeLineHistory_probackup(rt->recovery_target_tli); @@ -362,8 +362,9 @@ restore_backup(pgBackup *backup) char list_path[MAXPGPATH]; parray *files; int i; - pthread_t restore_threads[num_threads]; - restore_files_args *restore_threads_args[num_threads]; + /* arrays with meta info for multi threaded backup */ + pthread_t *restore_threads; + restore_files_args *restore_threads_args; bool restore_isok = true; if (backup->status != BACKUP_STATUS_OK) @@ -397,17 +398,21 @@ restore_backup(pgBackup *backup) pgBackupGetPath(backup, list_path, lengthof(list_path), DATABASE_FILE_LIST); files = dir_read_file_list(database_path, list_path); + restore_threads = (pthread_t *) palloc(sizeof(pthread_t)*num_threads); + restore_threads_args = (restore_files_args *) palloc(sizeof(restore_files_args)*num_threads); + /* setup threads */ for (i = 0; i < parray_num(files); i++) { pgFile *file = (pgFile *) parray_get(files, i); - __sync_lock_release(&file->lock); + pg_atomic_clear_flag(&file->lock); } /* Restore files into target directory */ for (i = 0; i < num_threads; i++) { - restore_files_args *arg = pg_malloc(sizeof(restore_files_args)); + restore_files_args *arg = &(restore_threads_args[i]); + arg->files = files; arg->backup = backup; /* By default there are some error */ @@ -415,23 +420,22 @@ restore_backup(pgBackup *backup) elog(LOG, "Start thread for num:%li", parray_num(files)); - restore_threads_args[i] = arg; - pthread_create(&restore_threads[i], NULL, - (void *(*)(void *)) restore_files, arg); + pthread_create(&restore_threads[i], NULL, restore_files, arg); } /* Wait theads */ for (i = 0; i < num_threads; i++) { pthread_join(restore_threads[i], NULL); - if (restore_threads_args[i]->ret == 1) + if (restore_threads_args[i].ret == 1) restore_isok = false; - - pg_free(restore_threads_args[i]); } if (!restore_isok) elog(ERROR, "Data files restoring failed"); + pfree(restore_threads); + pfree(restore_threads_args); + /* cleanup */ parray_walk(files, pgFileFree); parray_free(files); @@ -452,7 +456,7 @@ remove_deleted_files(pgBackup *backup) parray *files; parray *files_restored; char filelist_path[MAXPGPATH]; - int i; + int i; pgBackupGetPath(backup, filelist_path, lengthof(filelist_path), DATABASE_FILE_LIST); /* Read backup's filelist using target database path as base path */ @@ -702,7 +706,7 @@ check_tablespace_mapping(pgBackup *backup) /* * Restore files into $PGDATA. */ -static void +static void * restore_files(void *arg) { int i; @@ -714,7 +718,7 @@ restore_files(void *arg) char *rel_path; pgFile *file = (pgFile *) parray_get(arguments->files, i); - if (__sync_lock_test_and_set(&file->lock, 1) != 0) + if (!pg_atomic_test_set_flag(&file->lock)) continue; pgBackupGetPath(arguments->backup, from_root, @@ -779,6 +783,8 @@ restore_files(void *arg) /* Data files restoring is successful */ arguments->ret = 0; + + return NULL; } /* Create recovery.conf with given recovery target parameters */ @@ -787,9 +793,9 @@ create_recovery_conf(time_t backup_id, pgRecoveryTarget *rt, pgBackup *backup) { - char path[MAXPGPATH]; - FILE *fp; - bool need_restore_conf = false; + char path[MAXPGPATH]; + FILE *fp; + bool need_restore_conf = false; if (!backup->stream || (rt->time_specified || rt->xid_specified)) @@ -959,7 +965,8 @@ readTimeLineHistory_probackup(TimeLineID targetTLI) entry = pgut_new(TimeLineHistoryEntry); entry->tli = targetTLI; /* LSN in target timeline is valid */ - entry->end = (uint32) (-1UL << 32) | -1UL; + /* TODO ensure that -1UL --> -1L fix is correct */ + entry->end = (uint32) (-1L << 32) | -1L; parray_insert(result, 0, entry); return result; @@ -980,10 +987,13 @@ satisfy_recovery_target(const pgBackup *backup, const pgRecoveryTarget *rt) bool satisfy_timeline(const parray *timelines, const pgBackup *backup) { - int i; + int i; + for (i = 0; i < parray_num(timelines); i++) { - TimeLineHistoryEntry *timeline = (TimeLineHistoryEntry *) parray_get(timelines, i); + TimeLineHistoryEntry *timeline; + + timeline = (TimeLineHistoryEntry *) parray_get(timelines, i); if (backup->tli == timeline->tli && backup->stop_lsn < timeline->end) return true; @@ -1003,14 +1013,14 @@ parseRecoveryTargetOptions(const char *target_time, const char *target_name, const char *target_action) { - time_t dummy_time; - TransactionId dummy_xid; - bool dummy_bool; + time_t dummy_time; + TransactionId dummy_xid; + bool dummy_bool; /* * count the number of the mutually exclusive options which may specify * recovery target. If final value > 1, throw an error. */ - int recovery_target_specified = 0; + int recovery_target_specified = 0; pgRecoveryTarget *rt = pgut_new(pgRecoveryTarget); /* fill all options with default values */ diff --git a/src/status.c b/src/status.c index 1c7c6038..155a07f4 100644 --- a/src/status.c +++ b/src/status.c @@ -38,7 +38,7 @@ get_pgpid(void) snprintf(pid_file, lengthof(pid_file), "%s/postmaster.pid", pgdata); - pidf = fopen(pid_file, "r"); + pidf = fopen(pid_file, PG_BINARY_R); if (pidf == NULL) { /* No pid file, not an error on startup */ diff --git a/src/utils/logger.c b/src/utils/logger.c index 0a4f835b..8fd78739 100644 --- a/src/utils/logger.c +++ b/src/utils/logger.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include @@ -16,6 +15,7 @@ #include "logger.h" #include "pgut.h" +#include "thread.h" /* Logger parameters */ @@ -69,6 +69,9 @@ static bool exit_hook_registered = false; static bool loggin_in_progress = false; static pthread_mutex_t log_file_mutex = PTHREAD_MUTEX_INITIALIZER; +#ifdef WIN32 +static long mutex_initlock = 0; +#endif void init_logger(const char *root_path) @@ -138,11 +141,10 @@ exit_if_necessary(int elevel) } /* If this is not the main thread then don't call exit() */ + if (main_tid != pthread_self()) #ifdef WIN32 - if (main_tid != GetCurrentThreadId()) ExitThread(elevel); #else - if (!pthread_equal(main_tid, pthread_self())) pthread_exit(NULL); #endif else @@ -174,6 +176,16 @@ elog_internal(int elevel, bool file_only, const char *fmt, va_list args) /* * There is no need to lock if this is elog() from upper elog(). */ +#ifdef WIN32 + if (log_file_mutex == NULL) + { + while (InterlockedExchange(&mutex_initlock, 1) == 1) + /* loop, another thread own the lock */ ; + if (log_file_mutex == NULL) + pthread_mutex_init(&log_file_mutex, NULL); + InterlockedExchange(&mutex_initlock, 0); + } +#endif pthread_mutex_lock(&log_file_mutex); loggin_in_progress = true; @@ -550,7 +562,7 @@ open_logfile(FILE **file, const char *filename_format) { char buf[1024]; - control_file = fopen(control, "r"); + control_file = fopen(control, PG_BINARY_R); if (control_file == NULL) elog_stderr(ERROR, "cannot open rotation file \"%s\": %s", control, strerror(errno)); @@ -596,7 +608,7 @@ logfile_open: { time_t timestamp = time(NULL); - control_file = fopen(control, "w"); + control_file = fopen(control, PG_BINARY_W); if (control_file == NULL) elog_stderr(ERROR, "cannot open rotation file \"%s\": %s", control, strerror(errno)); diff --git a/src/utils/pgut.c b/src/utils/pgut.c index 56263cfa..1a7aae0b 100644 --- a/src/utils/pgut.c +++ b/src/utils/pgut.c @@ -42,12 +42,6 @@ static char *password = NULL; bool prompt_password = true; bool force_password = false; -#ifdef WIN32 -DWORD main_tid = 0; -#else -pthread_t main_tid = 0; -#endif - /* Database connections */ static PGcancel *volatile cancel_conn = NULL; @@ -995,7 +989,7 @@ longopts_to_optstring(const struct option opts[], const size_t len) s = result; for (i = 0; i < len; i++) { - if (!isprint(opts[i].val)) + if (!isprint(opts[i].val)) //opts[i].val > 128 || continue; *s++ = opts[i].val; if (opts[i].has_arg != no_argument) @@ -1052,6 +1046,7 @@ pgut_getopt(int argc, char **argv, pgut_option options[]) struct option *longopts; size_t len; + len = option_length(options); longopts = pgut_newarray(struct option, len + 1); option_copy(longopts, options, len); @@ -1059,6 +1054,7 @@ pgut_getopt(int argc, char **argv, pgut_option options[]) optstring = longopts_to_optstring(longopts, len); /* Assign named options */ + optind = 2; while ((c = getopt_long(argc, argv, optstring, longopts, &optindex)) != -1) { opt = option_find(c, options); @@ -1225,7 +1221,7 @@ get_next_token(const char *src, char *dst, const char *line) } else { - i = j = strcspn(s, "# \n\r\t\v"); + i = j = strcspn(s, "#\n\r\t\v");//removed space memcpy(dst, s, j); } diff --git a/src/utils/pgut.h b/src/utils/pgut.h index 803d2c57..a27cea83 100644 --- a/src/utils/pgut.h +++ b/src/utils/pgut.h @@ -15,7 +15,6 @@ #include "pqexpbuffer.h" #include -#include #include #include "logger.h" @@ -94,13 +93,6 @@ extern const char *PROGRAM_VERSION; extern const char *PROGRAM_URL; extern const char *PROGRAM_EMAIL; -/* ID of the main thread */ -#ifdef WIN32 -extern DWORD main_tid; -#else -extern pthread_t main_tid; -#endif - extern void pgut_help(bool details); /* diff --git a/src/utils/thread.c b/src/utils/thread.c new file mode 100644 index 00000000..da3544a1 --- /dev/null +++ b/src/utils/thread.c @@ -0,0 +1,80 @@ +/*------------------------------------------------------------------------- + * + * thread.c: - multi-platform pthread implementations. + * + * Copyright (c) 2018, Postgres Professional + * + *------------------------------------------------------------------------- + */ + +#include "thread.h" + +pthread_t main_tid = 0; + +#ifdef WIN32 + +typedef struct win32_pthread +{ + HANDLE handle; + void *(*routine) (void *); + void *arg; + void *result; +} win32_pthread; + +static unsigned __stdcall +win32_pthread_run(void *arg) +{ + win32_pthread *th = (win32_pthread *)arg; + + th->result = th->routine(th->arg); + + return 0; +} + +int +pthread_create(pthread_t *thread, + pthread_attr_t *attr, + void *(*start_routine) (void *), + void *arg) +{ + int save_errno; + win32_pthread *th; + + th = (win32_pthread *)pg_malloc(sizeof(win32_pthread)); + th->routine = start_routine; + th->arg = arg; + th->result = NULL; + + th->handle = (HANDLE)_beginthreadex(NULL, 0, win32_pthread_run, th, 0, NULL); + if (th->handle == NULL) + { + save_errno = errno; + free(th); + return save_errno; + } + + *thread = th; + return 0; +} + +int +pthread_join(pthread_t th, void **thread_return) +{ + if (th == NULL || th->handle == NULL) + return errno = EINVAL; + + if (WaitForSingleObject(th->handle, INFINITE) != WAIT_OBJECT_0) + { + _dosmaperr(GetLastError()); + return errno; + } + + if (thread_return) + *thread_return = th->result; + + CloseHandle(th->handle); + free(th); + return 0; +} + +#endif /* WIN32 */ diff --git a/src/utils/thread.h b/src/utils/thread.h new file mode 100644 index 00000000..0a113d58 --- /dev/null +++ b/src/utils/thread.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * thread.h: - multi-platform pthread implementations. + * + * Copyright (c) 2018, Postgres Professional + * + *------------------------------------------------------------------------- + */ + +#ifndef PROBACKUP_THREAD_H +#define PROBACKUP_THREAD_H + +#ifdef WIN32 +#include "port/pthread-win32.h" + +/* Use native win32 threads on Windows */ +typedef struct win32_pthread *pthread_t; +typedef int pthread_attr_t; + +#define PTHREAD_MUTEX_INITIALIZER NULL //{ NULL, 0 } +#define PTHREAD_ONCE_INIT false + +extern int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); +extern int pthread_join(pthread_t th, void **thread_return); +#else +/* Use platform-dependent pthread capability */ +#include +#endif + +extern pthread_t main_tid; + +#endif /* PROBACKUP_THREAD_H */ diff --git a/src/validate.c b/src/validate.c index afc7f07d..cb693268 100644 --- a/src/validate.c +++ b/src/validate.c @@ -11,10 +11,11 @@ #include "pg_probackup.h" #include -#include #include -static void pgBackupValidateFiles(void *arg); +#include "utils/thread.h" + +static void *pgBackupValidateFiles(void *arg); static void do_validate_instance(void); static bool corrupted_backup_found = false; @@ -42,8 +43,9 @@ pgBackupValidate(pgBackup *backup) parray *files; bool corrupted = false; bool validation_isok = true; - pthread_t validate_threads[num_threads]; - validate_files_args *validate_threads_args[num_threads]; + /* arrays with meta info for multi threaded validate */ + pthread_t *validate_threads; + validate_files_args *validate_threads_args; int i; /* Revalidation is attempted for DONE, ORPHAN and CORRUPT backups */ @@ -77,36 +79,44 @@ pgBackupValidate(pgBackup *backup) for (i = 0; i < parray_num(files); i++) { pgFile *file = (pgFile *) parray_get(files, i); - __sync_lock_release(&file->lock); + pg_atomic_clear_flag(&file->lock); } + /* init thread args with own file lists */ + validate_threads = (pthread_t *) palloc(sizeof(pthread_t) * num_threads); + validate_threads_args = (validate_files_args *) + palloc(sizeof(validate_files_args) * num_threads); + /* Validate files */ for (i = 0; i < num_threads; i++) { - validate_files_args *arg = pg_malloc(sizeof(validate_files_args)); + validate_files_args *arg = &(validate_threads_args[i]); + arg->files = files; arg->corrupted = false; /* By default there are some error */ arg->ret = 1; - validate_threads_args[i] = arg; - pthread_create(&validate_threads[i], NULL, - (void *(*)(void *)) pgBackupValidateFiles, arg); + pthread_create(&validate_threads[i], NULL, pgBackupValidateFiles, arg); } /* Wait theads */ for (i = 0; i < num_threads; i++) { + validate_files_args *arg = &(validate_threads_args[i]); + pthread_join(validate_threads[i], NULL); - if (validate_threads_args[i]->corrupted) + if (arg->corrupted) corrupted = true; - if (validate_threads_args[i]->ret == 1) + if (arg->ret == 1) validation_isok = false; - pg_free(validate_threads_args[i]); } if (!validation_isok) elog(ERROR, "Data files validation failed"); + pfree(validate_threads); + pfree(validate_threads_args); + /* cleanup */ parray_walk(files, pgFileFree); parray_free(files); @@ -127,10 +137,10 @@ pgBackupValidate(pgBackup *backup) * rather throw a WARNING and set arguments->corrupted = true. * This is necessary to update backup status. */ -static void +static void * pgBackupValidateFiles(void *arg) { - int i; + int i; validate_files_args *arguments = (validate_files_args *)arg; pg_crc32 crc; @@ -139,7 +149,7 @@ pgBackupValidateFiles(void *arg) struct stat st; pgFile *file = (pgFile *) parray_get(arguments->files, i); - if (__sync_lock_test_and_set(&file->lock, 1) != 0) + if (!pg_atomic_test_set_flag(&file->lock)) continue; if (interrupted) @@ -198,6 +208,8 @@ pgBackupValidateFiles(void *arg) /* Data files validation is successful */ arguments->ret = 0; + + return NULL; } /* @@ -267,7 +279,7 @@ do_validate_all(void) static void do_validate_instance(void) { - char *current_backup_id; + char *current_backup_id; int i; parray *backups; pgBackup *current_backup = NULL; diff --git a/win32build.pl b/win32build.pl new file mode 100644 index 00000000..14864181 --- /dev/null +++ b/win32build.pl @@ -0,0 +1,240 @@ +#!/usr/bin/perl +use JSON; +our $repack_version; +our $pgdir; +our $pgsrc; +if (@ARGV!=2) { + print STDERR "Usage $0 postgress-instalation-root pg-source-dir \n"; + exit 1; +} + + +our $liblist=""; + + +$pgdir = shift @ARGV; +$pgsrc = shift @ARGV if @ARGV; + + +our $arch = $ENV{'ARCH'} || "x64"; +$arch='Win32' if ($arch eq 'x86' || $arch eq 'X86'); +$arch='x64' if $arch eq 'X64'; + +$conffile = $pgsrc."/tools/msvc/config.pl"; + + +die 'Could not find config.pl' + unless (-f $conffile); + +our $config; +do $conffile; + + +if (! -d "$pgdir/bin" || !-d "$pgdir/include" || !-d "$pgdir/lib") { + print STDERR "Directory $pgdir doesn't look like root of postgresql installation\n"; + exit 1; +} +our $includepath=""; +our $libpath=""; +our $libpath32=""; +AddProject(); + +print "\n\n"; +print $libpath."\n"; +print $includepath."\n"; + +# open F,"<","META.json" or die "Cannot open META.json: $!\n"; +# { +# local $/ = undef; +# $decoded = decode_json(); +# $repack_version= $decoded->{'version'}; +# } + +# substitute new path in the project files + + + +preprocess_project("./msvs/template.pg_probackup.vcxproj","./msvs/pg_probackup.vcxproj"); + +exit 0; + + +sub preprocess_project { + my $in = shift; + my $out = shift; + our $pgdir; + our $adddir; + my $libs; + if (defined $adddir) { + $libs ="$adddir;"; + } else{ + $libs =""; + } + open IN,"<",$in or die "Cannot open $in: $!\n"; + open OUT,">",$out or die "Cannot open $out: $!\n"; + +# $includepath .= ";"; +# $libpath .= ";"; + + while () { + s/\@PGROOT\@/$pgdir/g; + s/\@ADDLIBS\@/$libpath/g; + s/\@ADDLIBS32\@/$libpath32/g; + s/\@PGSRC\@/$pgsrc/g; + s/\@ADDINCLUDE\@/$includepath/g; + + + print OUT $_; + } + close IN; + close OUT; + +} + + + +# my sub +sub AddLibrary +{ + $inc = shift; + if ($libpath ne '') + { + $libpath .= ';'; + } + $libpath .= $inc; + if ($libpath32 ne '') + { + $libpath32 .= ';'; + } + $libpath32 .= $inc; + +} +sub AddLibrary32 +{ + $inc = shift; + if ($libpath32 ne '') + { + $libpath32 .= ';'; + } + $libpath32 .= $inc; + +} +sub AddLibrary64 +{ + $inc = shift; + if ($libpath ne '') + { + $libpath .= ';'; + } + $libpath .= $inc; + +} + +sub AddIncludeDir +{ + # my ($self, $inc) = @_; + $inc = shift; + if ($includepath ne '') + { + $includepath .= ';'; + } + $includepath .= $inc; + +} + +sub AddProject +{ + # my ($self, $name, $type, $folder, $initialdir) = @_; + + if ($config->{zlib}) + { + AddIncludeDir($config->{zlib} . '\include'); + AddLibrary($config->{zlib} . '\lib\zdll.lib'); + } + if ($config->{openssl}) + { + AddIncludeDir($config->{openssl} . '\include'); + if (-e "$config->{openssl}/lib/VC/ssleay32MD.lib") + { + AddLibrary( + $config->{openssl} . '\lib\VC\ssleay32.lib', 1); + AddLibrary( + $config->{openssl} . '\lib\VC\libeay32.lib', 1); + } + else + { + # We don't expect the config-specific library to be here, + # so don't ask for it in last parameter + AddLibrary( + $config->{openssl} . '\lib\ssleay32.lib', 0); + AddLibrary( + $config->{openssl} . '\lib\libeay32.lib', 0); + } + } + if ($config->{nls}) + { + AddIncludeDir($config->{nls} . '\include'); + AddLibrary($config->{nls} . '\lib\libintl.lib'); + } + if ($config->{gss}) + { + AddIncludeDir($config->{gss} . '\inc\krb5'); + AddLibrary($config->{gss} . '\lib\i386\krb5_32.lib'); + AddLibrary($config->{gss} . '\lib\i386\comerr32.lib'); + AddLibrary($config->{gss} . '\lib\i386\gssapi32.lib'); + } + if ($config->{iconv}) + { + AddIncludeDir($config->{iconv} . '\include'); + AddLibrary($config->{iconv} . '\lib\iconv.lib'); + } + if ($config->{icu}) + { + AddIncludeDir($config->{icu} . '\include'); + AddLibrary32($config->{icu} . '\lib\icuin.lib'); + AddLibrary32($config->{icu} . '\lib\icuuc.lib'); + AddLibrary32($config->{icu} . '\lib\icudt.lib'); + AddLibrary64($config->{icu} . '\lib64\icuin.lib'); + AddLibrary64($config->{icu} . '\lib64\icuuc.lib'); + AddLibrary64($config->{icu} . '\lib64\icudt.lib'); + } + if ($config->{xml}) + { + AddIncludeDir($config->{xml} . '\include'); + AddIncludeDir($config->{xml} . '\include\libxml2'); + AddLibrary($config->{xml} . '\lib\libxml2.lib'); + } + if ($config->{xslt}) + { + AddIncludeDir($config->{xslt} . '\include'); + AddLibrary($config->{xslt} . '\lib\libxslt.lib'); + } + if ($config->{libedit}) + { + AddIncludeDir($config->{libedit} . '\include'); + # AddLibrary($config->{libedit} . "\\" . + # ($arch eq 'x64'? 'lib64': 'lib32').'\edit.lib'); + AddLibrary32($config->{libedit} . '\\lib32\edit.lib'); + AddLibrary64($config->{libedit} . '\\lib64\edit.lib'); + + + } + if ($config->{uuid}) + { + AddIncludeDir($config->{uuid} . '\include'); + AddLibrary($config->{uuid} . '\lib\uuid.lib'); + } + + if ($config->{zstd}) + { + AddIncludeDir($config->{zstd}); + # AddLibrary($config->{zstd}. "\\".($arch eq 'x64'? "zstdlib_x64.lib" : "zstdlib_x86.lib")); + AddLibrary32($config->{zstd}. "\\zstdlib_x86.lib"); + AddLibrary64($config->{zstd}. "\\zstdlib_x64.lib") ; + } + # return $proj; +} + + + + diff --git a/win32build96.pl b/win32build96.pl new file mode 100644 index 00000000..c869e485 --- /dev/null +++ b/win32build96.pl @@ -0,0 +1,240 @@ +#!/usr/bin/perl +use JSON; +our $repack_version; +our $pgdir; +our $pgsrc; +if (@ARGV!=2) { + print STDERR "Usage $0 postgress-instalation-root pg-source-dir \n"; + exit 1; +} + + +our $liblist=""; + + +$pgdir = shift @ARGV; +$pgsrc = shift @ARGV if @ARGV; + + +our $arch = $ENV{'ARCH'} || "x64"; +$arch='Win32' if ($arch eq 'x86' || $arch eq 'X86'); +$arch='x64' if $arch eq 'X64'; + +$conffile = $pgsrc."/tools/msvc/config.pl"; + + +die 'Could not find config.pl' + unless (-f $conffile); + +our $config; +do $conffile; + + +if (! -d "$pgdir/bin" || !-d "$pgdir/include" || !-d "$pgdir/lib") { + print STDERR "Directory $pgdir doesn't look like root of postgresql installation\n"; + exit 1; +} +our $includepath=""; +our $libpath=""; +our $libpath32=""; +AddProject(); + +print "\n\n"; +print $libpath."\n"; +print $includepath."\n"; + +# open F,"<","META.json" or die "Cannot open META.json: $!\n"; +# { +# local $/ = undef; +# $decoded = decode_json(); +# $repack_version= $decoded->{'version'}; +# } + +# substitute new path in the project files + + + +preprocess_project("./msvs/template.pg_probackup96.vcxproj","./msvs/pg_probackup.vcxproj"); + +exit 0; + + +sub preprocess_project { + my $in = shift; + my $out = shift; + our $pgdir; + our $adddir; + my $libs; + if (defined $adddir) { + $libs ="$adddir;"; + } else{ + $libs =""; + } + open IN,"<",$in or die "Cannot open $in: $!\n"; + open OUT,">",$out or die "Cannot open $out: $!\n"; + +# $includepath .= ";"; +# $libpath .= ";"; + + while () { + s/\@PGROOT\@/$pgdir/g; + s/\@ADDLIBS\@/$libpath/g; + s/\@ADDLIBS32\@/$libpath32/g; + s/\@PGSRC\@/$pgsrc/g; + s/\@ADDINCLUDE\@/$includepath/g; + + + print OUT $_; + } + close IN; + close OUT; + +} + + + +# my sub +sub AddLibrary +{ + $inc = shift; + if ($libpath ne '') + { + $libpath .= ';'; + } + $libpath .= $inc; + if ($libpath32 ne '') + { + $libpath32 .= ';'; + } + $libpath32 .= $inc; + +} +sub AddLibrary32 +{ + $inc = shift; + if ($libpath32 ne '') + { + $libpath32 .= ';'; + } + $libpath32 .= $inc; + +} +sub AddLibrary64 +{ + $inc = shift; + if ($libpath ne '') + { + $libpath .= ';'; + } + $libpath .= $inc; + +} + +sub AddIncludeDir +{ + # my ($self, $inc) = @_; + $inc = shift; + if ($includepath ne '') + { + $includepath .= ';'; + } + $includepath .= $inc; + +} + +sub AddProject +{ + # my ($self, $name, $type, $folder, $initialdir) = @_; + + if ($config->{zlib}) + { + AddIncludeDir($config->{zlib} . '\include'); + AddLibrary($config->{zlib} . '\lib\zdll.lib'); + } + if ($config->{openssl}) + { + AddIncludeDir($config->{openssl} . '\include'); + if (-e "$config->{openssl}/lib/VC/ssleay32MD.lib") + { + AddLibrary( + $config->{openssl} . '\lib\VC\ssleay32.lib', 1); + AddLibrary( + $config->{openssl} . '\lib\VC\libeay32.lib', 1); + } + else + { + # We don't expect the config-specific library to be here, + # so don't ask for it in last parameter + AddLibrary( + $config->{openssl} . '\lib\ssleay32.lib', 0); + AddLibrary( + $config->{openssl} . '\lib\libeay32.lib', 0); + } + } + if ($config->{nls}) + { + AddIncludeDir($config->{nls} . '\include'); + AddLibrary($config->{nls} . '\lib\libintl.lib'); + } + if ($config->{gss}) + { + AddIncludeDir($config->{gss} . '\inc\krb5'); + AddLibrary($config->{gss} . '\lib\i386\krb5_32.lib'); + AddLibrary($config->{gss} . '\lib\i386\comerr32.lib'); + AddLibrary($config->{gss} . '\lib\i386\gssapi32.lib'); + } + if ($config->{iconv}) + { + AddIncludeDir($config->{iconv} . '\include'); + AddLibrary($config->{iconv} . '\lib\iconv.lib'); + } + if ($config->{icu}) + { + AddIncludeDir($config->{icu} . '\include'); + AddLibrary32($config->{icu} . '\lib\icuin.lib'); + AddLibrary32($config->{icu} . '\lib\icuuc.lib'); + AddLibrary32($config->{icu} . '\lib\icudt.lib'); + AddLibrary64($config->{icu} . '\lib64\icuin.lib'); + AddLibrary64($config->{icu} . '\lib64\icuuc.lib'); + AddLibrary64($config->{icu} . '\lib64\icudt.lib'); + } + if ($config->{xml}) + { + AddIncludeDir($config->{xml} . '\include'); + AddIncludeDir($config->{xml} . '\include\libxml2'); + AddLibrary($config->{xml} . '\lib\libxml2.lib'); + } + if ($config->{xslt}) + { + AddIncludeDir($config->{xslt} . '\include'); + AddLibrary($config->{xslt} . '\lib\libxslt.lib'); + } + if ($config->{libedit}) + { + AddIncludeDir($config->{libedit} . '\include'); + # AddLibrary($config->{libedit} . "\\" . + # ($arch eq 'x64'? 'lib64': 'lib32').'\edit.lib'); + AddLibrary32($config->{libedit} . '\\lib32\edit.lib'); + AddLibrary64($config->{libedit} . '\\lib64\edit.lib'); + + + } + if ($config->{uuid}) + { + AddIncludeDir($config->{uuid} . '\include'); + AddLibrary($config->{uuid} . '\lib\uuid.lib'); + } + + if ($config->{zstd}) + { + AddIncludeDir($config->{zstd}); + # AddLibrary($config->{zstd}. "\\".($arch eq 'x64'? "zstdlib_x64.lib" : "zstdlib_x86.lib")); + AddLibrary32($config->{zstd}. "\\zstdlib_x86.lib"); + AddLibrary64($config->{zstd}. "\\zstdlib_x64.lib") ; + } + # return $proj; +} + + + + diff --git a/win32build_2.pl b/win32build_2.pl new file mode 100644 index 00000000..a4f75553 --- /dev/null +++ b/win32build_2.pl @@ -0,0 +1,219 @@ +#!/usr/bin/perl +use JSON; +our $repack_version; +our $pgdir; +our $pgsrc; +if (@ARGV!=2) { + print STDERR "Usage $0 postgress-instalation-root pg-source-dir \n"; + exit 1; +} + + +our $liblist=""; + + +$pgdir = shift @ARGV; +$pgsrc = shift @ARGV if @ARGV; + + +our $arch = $ENV{'ARCH'} || "x64"; +$arch='Win32' if ($arch eq 'x86' || $arch eq 'X86'); +$arch='x64' if $arch eq 'X64'; + +$conffile = $pgsrc."/tools/msvc/config.pl"; + + +die 'Could not find config.pl' + unless (-f $conffile); + +our $config; +do $conffile; + + +if (! -d "$pgdir/bin" || !-d "$pgdir/include" || !-d "$pgdir/lib") { + print STDERR "Directory $pgdir doesn't look like root of postgresql installation\n"; + exit 1; +} +our $includepath=""; +our $libpath=""; +AddProject(); + +print "\n\n"; +print $libpath."\n"; +print $includepath."\n"; + +# open F,"<","META.json" or die "Cannot open META.json: $!\n"; +# { +# local $/ = undef; +# $decoded = decode_json(); +# $repack_version= $decoded->{'version'}; +# } + +# substitute new path in the project files + + + +preprocess_project("./msvs/template.pg_probackup_2.vcxproj","./msvs/pg_probackup.vcxproj"); + +exit 0; + + +sub preprocess_project { + my $in = shift; + my $out = shift; + our $pgdir; + our $adddir; + my $libs; + if (defined $adddir) { + $libs ="$adddir;"; + } else{ + $libs =""; + } + open IN,"<",$in or die "Cannot open $in: $!\n"; + open OUT,">",$out or die "Cannot open $out: $!\n"; + +# $includepath .= ";"; +# $libpath .= ";"; + + while () { + s/\@PGROOT\@/$pgdir/g; + s/\@ADDLIBS\@/$libpath/g; + s/\@PGSRC\@/$pgsrc/g; + s/\@ADDINCLUDE\@/$includepath/g; + + + print OUT $_; + } + close IN; + close OUT; + +} + + + +# my sub +sub AddLibrary +{ + $inc = shift; + if ($libpath ne '') + { + $libpath .= ';'; + } + $libpath .= $inc; + +} +sub AddIncludeDir +{ + # my ($self, $inc) = @_; + $inc = shift; + if ($includepath ne '') + { + $includepath .= ';'; + } + $includepath .= $inc; + +} + +sub AddProject +{ + # my ($self, $name, $type, $folder, $initialdir) = @_; + + if ($config->{zlib}) + { + AddIncludeDir($config->{zlib} . '\include'); + AddLibrary($config->{zlib} . '\lib\zdll.lib'); + } + if ($config->{openssl}) + { + AddIncludeDir($config->{openssl} . '\include'); + if (-e "$config->{openssl}/lib/VC/ssleay32MD.lib") + { + AddLibrary( + $config->{openssl} . '\lib\VC\ssleay32.lib', 1); + AddLibrary( + $config->{openssl} . '\lib\VC\libeay32.lib', 1); + } + else + { + # We don't expect the config-specific library to be here, + # so don't ask for it in last parameter + AddLibrary( + $config->{openssl} . '\lib\ssleay32.lib', 0); + AddLibrary( + $config->{openssl} . '\lib\libeay32.lib', 0); + } + } + if ($config->{nls}) + { + AddIncludeDir($config->{nls} . '\include'); + AddLibrary($config->{nls} . '\lib\libintl.lib'); + } + if ($config->{gss}) + { + AddIncludeDir($config->{gss} . '\inc\krb5'); + AddLibrary($config->{gss} . '\lib\i386\krb5_32.lib'); + AddLibrary($config->{gss} . '\lib\i386\comerr32.lib'); + AddLibrary($config->{gss} . '\lib\i386\gssapi32.lib'); + } + if ($config->{iconv}) + { + AddIncludeDir($config->{iconv} . '\include'); + AddLibrary($config->{iconv} . '\lib\iconv.lib'); + } + if ($config->{icu}) + { + AddIncludeDir($config->{icu} . '\include'); + if ($arch eq 'Win32') + { + AddLibrary($config->{icu} . '\lib\icuin.lib'); + AddLibrary($config->{icu} . '\lib\icuuc.lib'); + AddLibrary($config->{icu} . '\lib\icudt.lib'); + } + else + { + AddLibrary($config->{icu} . '\lib64\icuin.lib'); + AddLibrary($config->{icu} . '\lib64\icuuc.lib'); + AddLibrary($config->{icu} . '\lib64\icudt.lib'); + } + } + if ($config->{xml}) + { + AddIncludeDir($config->{xml} . '\include'); + AddIncludeDir($config->{xml} . '\include\libxml2'); + AddLibrary($config->{xml} . '\lib\libxml2.lib'); + } + if ($config->{xslt}) + { + AddIncludeDir($config->{xslt} . '\include'); + AddLibrary($config->{xslt} . '\lib\libxslt.lib'); + } + if ($config->{libedit}) + { + AddIncludeDir($config->{libedit} . '\include'); + AddLibrary($config->{libedit} . "\\" . + ($arch eq 'x64'? 'lib64': 'lib32').'\edit.lib'); + } + if ($config->{uuid}) + { + AddIncludeDir($config->{uuid} . '\include'); + AddLibrary($config->{uuid} . '\lib\uuid.lib'); + } + if ($config->{libedit}) + { + AddIncludeDir($config->{libedit} . '\include'); + AddLibrary($config->{libedit} . "\\" . + ($arch eq 'x64'? 'lib64': 'lib32').'\edit.lib'); + } + if ($config->{zstd}) + { + AddIncludeDir($config->{zstd}); + AddLibrary($config->{zstd}. "\\". + ($arch eq 'x64'? "zstdlib_x64.lib" : "zstdlib_x86.lib") + ); + } + # return $proj; +} + + + +