00001 00004 /* Copyright (C) 2007 Olly Betts 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License as 00008 * published by the Free Software Foundation; either version 2 of the 00009 * License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 #include <config.h> 00022 00023 #include "backendmanager_multi.h" 00024 00025 #include "index_utils.h" 00026 #include "utils.h" 00027 00028 #include <cstdio> 00029 #include <cstring> 00030 #include "safeerrno.h" 00031 00032 using namespace std; 00033 00034 BackendManagerMulti::~BackendManagerMulti() { } 00035 00036 const char * 00037 BackendManagerMulti::get_dbtype() const 00038 { 00039 return "multi"; 00040 } 00041 00042 #define NUMBER_OF_SUB_DBS 2 00043 00044 string 00045 BackendManagerMulti::createdb_multi(const vector<string> & files) 00046 { 00047 create_dir_if_needed(".multi"); 00048 00049 string dbpath = ".multi/db"; 00050 vector<string>::const_iterator i; 00051 for (i = files.begin(); i != files.end(); ++i) { 00052 dbpath += "__"; 00053 dbpath += *i; 00054 } 00055 00056 if (file_exists(dbpath)) return dbpath; 00057 00058 string tmpfile = dbpath; 00059 tmpfile += ".tmp"; 00060 ofstream out(tmpfile.c_str()); 00061 if (!out.is_open()) { 00062 string msg = "Couldn't create file '"; 00063 msg += tmpfile; 00064 msg += "' ("; 00065 msg += strerror(errno); 00066 msg += ')'; 00067 throw msg; 00068 } 00069 00070 // Open NUMBER_OF_SUB_DBS databases and index files to the alternately so a 00071 // multi-db combining them contains the documents in the expected order. 00072 Xapian::WritableDatabase dbs[NUMBER_OF_SUB_DBS]; 00073 for (size_t n = 0; n < NUMBER_OF_SUB_DBS; ++n) { 00074 string subdbdir = dbpath; 00075 subdbdir += "___"; 00076 subdbdir += om_tostring(n); 00077 #ifdef XAPIAN_HAS_FLINT_BACKEND 00078 dbs[n] = Xapian::Flint::open(subdbdir, Xapian::DB_CREATE_OR_OVERWRITE); 00079 out << "flint " << subdbdir << '\n'; 00080 #else 00081 dbs[n] = Xapian::Quartz::open(subdbdir, Xapian::DB_CREATE_OR_OVERWRITE); 00082 out << "quartz " << subdbdir << '\n'; 00083 #endif 00084 } 00085 out.close(); 00086 00087 size_t c = 0; 00088 FileIndexer f(get_datadir(), files); 00089 while (f) { 00090 dbs[c].add_document(f.next()); 00091 c = (c + 1) % NUMBER_OF_SUB_DBS; 00092 } 00093 00094 rename(tmpfile.c_str(), dbpath.c_str()); 00095 00096 return dbpath; 00097 } 00098 00099 Xapian::Database 00100 BackendManagerMulti::get_database(const vector<string> & files) 00101 { 00102 return Xapian::Auto::open_stub(createdb_multi(files)); 00103 } 00104 00105 Xapian::Database 00106 BackendManagerMulti::get_database(const string & file) 00107 { 00108 return BackendManagerMulti::get_database(vector<string>(1, file)); 00109 } 00110 00111 Xapian::WritableDatabase 00112 BackendManagerMulti::get_writable_database(const string &, const string &) 00113 { 00114 throw Xapian::UnimplementedError("Multi-databases don't support writing"); 00115 }