00001
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <config.h>
00024
00025 #include <xapian.h>
00026
00027 #include <cstdlib>
00028 #include <iostream>
00029
00030 #include "gnu_getopt.h"
00031
00032 using namespace std;
00033
00034 #define PROG_NAME "xapian-compact"
00035 #define PROG_DESC "Compact a database, or merge and compact several"
00036
00037 #define OPT_HELP 1
00038 #define OPT_VERSION 2
00039 #define OPT_NO_RENUMBER 3
00040
00041 static void show_usage() {
00042 cout << "Usage: "PROG_NAME" [OPTIONS] SOURCE_DATABASE... DESTINATION_DATABASE\n\n"
00043 "Options:\n"
00044 " -b, --blocksize Set the blocksize in bytes (e.g. 4096) or K (e.g. 4K)\n"
00045 " (must be between 2K and 64K and a power of 2, default 8K)\n"
00046 " -n, --no-full Disable full compaction\n"
00047 " -F, --fuller Enable fuller compaction (not recommended if you plan to\n"
00048 " update the compacted database)\n"
00049 " -m, --multipass If merging more than 3 databases, merge the postlists in\n"
00050 " multiple passes (which is generally faster but requires\n"
00051 " more disk space for temporary files)\n"
00052 " --no-renumber Preserve the numbering of document ids (useful if you have\n"
00053 " external references to them, or have set them to match\n"
00054 " unique ids from an external source). Currently this\n"
00055 " option is only supported when merging databases if they\n"
00056 " have disjoint ranges of used document ids\n"
00057 " --help display this help and exit\n"
00058 " --version output version information and exit" << endl;
00059 }
00060
00061 class MyCompactor : public Xapian::Compactor {
00062 bool quiet;
00063
00064 public:
00065 MyCompactor() : quiet(false) { }
00066
00067 void set_quiet(bool quiet_) { quiet = quiet_; }
00068
00069 void set_status(const string & table, const string & status);
00070
00071 string
00072 resolve_duplicate_metadata(const string & key,
00073 size_t n,
00074 const string tags[]);
00075 };
00076
00077 void
00078 MyCompactor::set_status(const string & table, const string & status)
00079 {
00080 if (quiet)
00081 return;
00082 if (!status.empty())
00083 cout << '\r' << table << ": " << status << endl;
00084 else
00085 cout << table << " ..." << flush;
00086 }
00087
00088 string
00089 MyCompactor::resolve_duplicate_metadata(const string & key,
00090 size_t n,
00091 const string tags[])
00092 {
00093 (void)key;
00094 while (--n) {
00095 if (tags[0] != tags[n]) {
00096 cerr << "Warning: duplicate user metadata key with different tag value - picking value from first source database with a non-empty value" << endl;
00097 break;
00098 }
00099 }
00100 return tags[0];
00101 }
00102
00103 int
00104 main(int argc, char **argv)
00105 {
00106 const char * opts = "b:nFmq";
00107 const struct option long_opts[] = {
00108 {"fuller", no_argument, 0, 'F'},
00109 {"no-full", no_argument, 0, 'n'},
00110 {"multipass", no_argument, 0, 'm'},
00111 {"blocksize", required_argument, 0, 'b'},
00112 {"no-renumber", no_argument, 0, OPT_NO_RENUMBER},
00113 {"quiet", no_argument, 0, 'q'},
00114 {"help", no_argument, 0, OPT_HELP},
00115 {"version", no_argument, 0, OPT_VERSION},
00116 {NULL, 0, 0, 0}
00117 };
00118
00119 MyCompactor compactor;
00120
00121 int c;
00122 while ((c = gnu_getopt_long(argc, argv, opts, long_opts, 0)) != -1) {
00123 switch (c) {
00124 case 'b': {
00125 char *p;
00126 size_t block_size = strtoul(optarg, &p, 10);
00127 if (block_size <= 64 && (*p == 'K' || *p == 'k')) {
00128 ++p;
00129 block_size *= 1024;
00130 }
00131 if (*p || block_size < 2048 || block_size > 65536 ||
00132 (block_size & (block_size - 1)) != 0) {
00133 cerr << PROG_NAME": Bad value '" << optarg
00134 << "' passed for blocksize, must be a power of 2 between 2K and 64K"
00135 << endl;
00136 exit(1);
00137 }
00138 compactor.set_block_size(block_size);
00139 break;
00140 }
00141 case 'n':
00142 compactor.set_compaction_level(compactor.STANDARD);
00143 break;
00144 case 'F':
00145 compactor.set_compaction_level(compactor.FULLER);
00146 break;
00147 case 'm':
00148 compactor.set_multipass(true);
00149 break;
00150 case OPT_NO_RENUMBER:
00151 compactor.set_renumber(false);
00152 break;
00153 case 'q':
00154 compactor.set_quiet(true);
00155 break;
00156 case OPT_HELP:
00157 cout << PROG_NAME" - "PROG_DESC"\n\n";
00158 show_usage();
00159 exit(0);
00160 case OPT_VERSION:
00161 cout << PROG_NAME" - "PACKAGE_STRING << endl;
00162 exit(0);
00163 default:
00164 show_usage();
00165 exit(1);
00166 }
00167 }
00168
00169 if (argc - optind < 2) {
00170 show_usage();
00171 exit(1);
00172 }
00173
00174
00175 compactor.set_destdir(argv[argc - 1]);
00176
00177 try {
00178 for (int i = optind; i < argc - 1; ++i) {
00179 compactor.add_source(argv[i]);
00180 }
00181
00182 compactor.compact();
00183 } catch (const Xapian::Error &error) {
00184 cerr << argv[0] << ": " << error.get_description() << endl;
00185 exit(1);
00186 } catch (const char * msg) {
00187 cerr << argv[0] << ": " << msg << endl;
00188 exit(1);
00189 }
00190 }