00001
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include "replicatetcpclient.h"
00025
00026 #include <xapian.h>
00027
00028 #include "gnu_getopt.h"
00029 #include "stringutils.h"
00030 #include "safeunistd.h"
00031
00032 #include <iostream>
00033
00034 using namespace std;
00035
00036 #define PROG_NAME "xapian-replicate"
00037 #define PROG_DESC "Replicate a database from a master server to a local copy"
00038
00039 #define OPT_HELP 1
00040 #define OPT_VERSION 2
00041
00042
00043 #define DEFAULT_INTERVAL 60
00044
00045
00046 #define READER_CLOSE_TIME 30
00047
00048 static void show_usage() {
00049 cout << "Usage: "PROG_NAME" [OPTIONS] DATABASE\n\n"
00050 "Options:\n"
00051 " -h, --host=HOST host to connect to (required)\n"
00052 " -p, --port=PORT port to connect to (required)\n"
00053 " -m, --master=DB replicate database DB from the master (default: DATABASE)\n"
00054 " -i, --interval=N wait N seconds between each connection to the master\n"
00055 " (default: "STRINGIZE(DEFAULT_INTERVAL)")\n"
00056 " -r, --reader-time=N wait N seconds to allow readers time to close before\n"
00057 " applying repeated changesets (default: "STRINGIZE(READER_CLOSE_TIME)")\n"
00058 " -o, --one-shot replicate only once and then exit\n"
00059 " -v, --verbose be more verbose\n"
00060 " --help display this help and exit\n"
00061 " --version output version information and exit" << endl;
00062 }
00063
00064 int
00065 main(int argc, char **argv)
00066 {
00067 const char * opts = "h:p:m:i:r:ov";
00068 const struct option long_opts[] = {
00069 {"host", required_argument, 0, 'h'},
00070 {"port", required_argument, 0, 'p'},
00071 {"master", required_argument, 0, 'm'},
00072 {"interval", required_argument, 0, 'i'},
00073 {"reader-time", required_argument, 0, 'r'},
00074 {"one-shot", no_argument, 0, 'o'},
00075 {"verbose", no_argument, 0, 'v'},
00076 {"help", no_argument, 0, OPT_HELP},
00077 {"version", no_argument, 0, OPT_VERSION},
00078 {NULL, 0, 0, 0}
00079 };
00080
00081 string host;
00082 int port = 0;
00083 string masterdb;
00084 int interval = DEFAULT_INTERVAL;
00085 bool one_shot = false;
00086 bool verbose = false;
00087 int reader_close_time = READER_CLOSE_TIME;
00088
00089 int c;
00090 while ((c = gnu_getopt_long(argc, argv, opts, long_opts, 0)) != -1) {
00091 switch (c) {
00092 case 'h':
00093 host.assign(optarg);
00094 break;
00095 case 'p':
00096 port = atoi(optarg);
00097 break;
00098 case 'm':
00099 masterdb.assign(optarg);
00100 break;
00101 case 'i':
00102 interval = atoi(optarg);
00103 break;
00104 case 'r':
00105 reader_close_time = atoi(optarg);
00106 break;
00107 case 'o':
00108 one_shot = true;
00109 break;
00110 case 'v':
00111 verbose = true;
00112 break;
00113 case OPT_HELP:
00114 cout << PROG_NAME" - "PROG_DESC"\n\n";
00115 show_usage();
00116 exit(0);
00117 case OPT_VERSION:
00118 cout << PROG_NAME" - "PACKAGE_STRING << endl;
00119 exit(0);
00120 default:
00121 show_usage();
00122 exit(1);
00123 }
00124 }
00125
00126 if (argc - optind != 1) {
00127 show_usage();
00128 exit(1);
00129 }
00130
00131 if (host.empty()) {
00132 cout << "Host required - specify with --host=HOST\n\n";
00133 show_usage();
00134 exit(1);
00135 }
00136
00137 if (port == 0) {
00138 cout << "Port required - specify with --port=PORT\n\n";
00139 show_usage();
00140 exit(1);
00141 }
00142
00143
00144 string dbpath(argv[optind]);
00145
00146 if (masterdb.empty())
00147 masterdb = dbpath;
00148
00149 while (true) {
00150 try {
00151 if (verbose) {
00152 cout << "Connecting to " << host << ":" << port << endl;
00153 }
00154 ReplicateTcpClient client(host, port, 10000);
00155 if (verbose) {
00156 cout << "Getting update for " << dbpath << " from "
00157 << masterdb << endl;
00158 }
00159 Xapian::ReplicationInfo info;
00160 client.update_from_master(dbpath, masterdb, info,
00161 reader_close_time);
00162 if (verbose) {
00163 cout << "Update complete: " <<
00164 info.fullcopy_count << " copies, " <<
00165 info.changeset_count << " changesets, " <<
00166 (info.changed ? "new live database" : "no changes to live database") <<
00167 endl;
00168 if (info.fullcopy_count > 0 && !info.changed) {
00169 cout <<
00170 "Replication using a full copy failed. This is usually due to changes being\n"
00171 "made at remote end too frequently. Ensure that sufficient changesets are\n"
00172 "present at remote end by setting XAPIAN_MAX_CHANGESETS" << endl;
00173 }
00174 }
00175 } catch (const Xapian::NetworkError &error) {
00176
00177
00178
00179 cerr << argv[0] << ": " << error.get_description() << endl;
00180
00181
00182
00183
00184 if (one_shot)
00185 exit(1);
00186 } catch (const Xapian::Error &error) {
00187 cerr << argv[0] << ": " << error.get_description() << endl;
00188 exit(1);
00189 } catch (const exception &e) {
00190 cerr << "Caught standard exception: " << e.what() << endl;
00191 exit(1);
00192 } catch (...) {
00193 cerr << "Caught unknown exception" << endl;
00194 exit(1);
00195 }
00196 if (one_shot) break;
00197 sleep(interval);
00198 }
00199 }