1 /*
2 * Copyright 2005-2009 Fabrice Colin
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #include <iostream>
20
21 #include "XapianDatabaseFactory.h"
22
23 using std::clog;
24 using std::endl;
25 using std::string;
26 using std::map;
27 using std::pair;
28
29 pthread_mutex_t XapianDatabaseFactory::m_mutex = PTHREAD_MUTEX_INITIALIZER;
30 map<string, XapianDatabase *> XapianDatabaseFactory::m_databases;
31 bool XapianDatabaseFactory::m_closed = false;
32
XapianDatabaseFactory()33 XapianDatabaseFactory::XapianDatabaseFactory()
34 {
35 }
36
~XapianDatabaseFactory()37 XapianDatabaseFactory::~XapianDatabaseFactory()
38 {
39 }
40
41 /// Merges two databases together and add the result to the list.
mergeDatabases(const string & name,XapianDatabase * pFirst,XapianDatabase * pSecond)42 bool XapianDatabaseFactory::mergeDatabases(const string &name,
43 XapianDatabase *pFirst, XapianDatabase *pSecond)
44 {
45 if (m_closed == true)
46 {
47 return false;
48 }
49
50 map<string, XapianDatabase *>::iterator dbIter = m_databases.find(name);
51 if (dbIter != m_databases.end())
52 {
53 return false;
54 }
55
56 // Create the new database
57 XapianDatabase *pDb = new XapianDatabase(name, pFirst, pSecond);
58
59 // Insert it into the map
60 pair<map<string, XapianDatabase *>::iterator, bool> insertPair = m_databases.insert(pair<string, XapianDatabase *>(name, pDb));
61 // Was it inserted ?
62 if (insertPair.second == false)
63 {
64 // No, it wasn't : delete the object
65 delete pDb;
66
67 return false;
68 }
69
70 return true;
71 }
72
73 /// Returns a XapianDatabase pointer; NULL if unavailable.
getDatabase(const string & location,bool readOnly,bool overwrite)74 XapianDatabase *XapianDatabaseFactory::getDatabase(const string &location,
75 bool readOnly, bool overwrite)
76 {
77 XapianDatabase *pDb = NULL;
78
79 if ((m_closed == true) ||
80 (location.empty() == true))
81 {
82 return NULL;
83 }
84
85 // Lock the map
86 if (pthread_mutex_lock(&m_mutex) != 0)
87 {
88 return NULL;
89 }
90
91 // Is the database already open ?
92 map<string, XapianDatabase *>::iterator dbIter = m_databases.find(location);
93 if (dbIter != m_databases.end())
94 {
95 pDb = dbIter->second;
96
97 // Overwrite the database ?
98 if (overwrite == true)
99 {
100 dbIter->second = NULL;
101 #ifdef DEBUG
102 clog << "XapianDatabaseFactory::getDatabase: closing " << dbIter->first << endl;
103 #endif
104 m_databases.erase(dbIter);
105 delete pDb;
106
107 dbIter = m_databases.end();
108 }
109 }
110
111 // Open the database ?
112 if (dbIter == m_databases.end())
113 {
114 // Create a new instance
115 pDb = new XapianDatabase(location, readOnly, overwrite);
116 // Insert it into the map
117 pair<map<string, XapianDatabase *>::iterator, bool> insertPair = m_databases.insert(pair<string, XapianDatabase *>(location, pDb));
118 // Was it inserted ?
119 if (insertPair.second == false)
120 {
121 // No, it wasn't : delete the object
122 delete pDb;
123 pDb = NULL;
124 }
125 }
126
127 // Unlock the map
128 pthread_mutex_unlock(&m_mutex);
129
130 return pDb;
131 }
132
133 /// Closes all databases.
closeAll(void)134 void XapianDatabaseFactory::closeAll(void)
135 {
136 if (m_databases.empty() == true)
137 {
138 return;
139 }
140
141 // Lock the map
142 // FIXME: another thread may have a database and try and lock it after the loop below deletes it
143 if (pthread_mutex_lock(&m_mutex) != 0)
144 {
145 return;
146 }
147 m_closed = true;
148
149 // Close merged databases first
150 std::map<std::string, XapianDatabase *>::iterator dbIter = m_databases.begin();
151 while (dbIter != m_databases.end())
152 {
153 XapianDatabase *pDb = dbIter->second;
154
155 if (pDb->isMerge() == false)
156 {
157 ++dbIter;
158 continue;
159 }
160
161 std::map<std::string, XapianDatabase *>::iterator nextIter = dbIter;
162 ++nextIter;
163 #ifdef DEBUG
164 clog << "XapianDatabaseFactory::closeAll: closing " << dbIter->first << endl;
165 #endif
166
167 // Remove from the map
168 dbIter->second = NULL;
169 m_databases.erase(dbIter);
170
171 Xapian::Database *pIndex = pDb->readLock();
172 pDb->unlock();
173 // Close the database
174 delete pDb;
175
176 dbIter = nextIter;
177 }
178 // Now close all other databases
179 dbIter = m_databases.begin();
180 while (dbIter != m_databases.end())
181 {
182 XapianDatabase *pDb = dbIter->second;
183 Xapian::Database *pIndex = NULL;
184 #ifdef DEBUG
185 clog << "XapianDatabaseFactory::closeAll: closing " << dbIter->first << endl;
186 #endif
187
188 // Remove from the map
189 dbIter->second = NULL;
190 m_databases.erase(dbIter);
191
192 if (pDb->isWritable() == true)
193 {
194 pIndex = pDb->writeLock();
195 }
196 else
197 {
198 pIndex = pDb->readLock();
199 }
200 pDb->unlock();
201 // Close the database
202 delete pDb;
203
204 dbIter = m_databases.begin();
205 }
206
207 // Unlock the map
208 pthread_mutex_unlock(&m_mutex);
209 }
210