1 /* $Id: netstorage_gc_database.cpp 534245 2017-04-25 18:15:43Z satskyse $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Sergey Satskiy
27 *
28 */
29
30 #include <ncbi_pch.hpp>
31
32 #include <corelib/ncbidiag.hpp>
33 #include <corelib/resource_info.hpp>
34 #include <corelib/request_ctx.hpp>
35 #include <corelib/ncbistd.hpp>
36 #include <connect/services/netstorage.hpp>
37
38 #include "netstorage_gc_database.hpp"
39 #include "netstorage_gc_exception.hpp"
40
41
42 BEGIN_NCBI_SCOPE
43
44
CNetStorageGCDatabase(const CNcbiRegistry & reg,bool verbose,unsigned int timeout)45 CNetStorageGCDatabase::CNetStorageGCDatabase(const CNcbiRegistry & reg,
46 bool verbose,
47 unsigned int timeout)
48 : m_Verbose(verbose), m_Db(NULL), m_Timeout(timeout, 0)
49 {
50 x_CreateDatabase(reg);
51 try {
52 x_Connect();
53 } catch (...) {
54 delete m_Db;
55 throw;
56 }
57 }
58
59
x_Connect(void)60 void CNetStorageGCDatabase::x_Connect(void)
61 {
62 try {
63 if (m_Verbose)
64 cout << "Connecting to the NetStorage meta info database..."
65 << endl;
66 m_Db->Connect();
67 if (m_Verbose)
68 cout << "Connected" << endl;
69 } catch (...) {
70 cerr << "Error connecting to the NetStorage meta info database" << endl;
71 throw;
72 }
73 }
74
75
~CNetStorageGCDatabase(void)76 CNetStorageGCDatabase::~CNetStorageGCDatabase(void)
77 {
78 if (m_Verbose)
79 cout << "Closing the NetStorage meta info database connection..."
80 << endl;
81 m_Db->Close();
82 if (m_Verbose)
83 cout << "Closed" << endl;
84 delete m_Db;
85 }
86
87
GetAppLock(void)88 void CNetStorageGCDatabase::GetAppLock(void)
89 {
90 if (m_Verbose)
91 cout << "Getting the application lock..." << endl;
92
93 try {
94 CQuery query = m_Db->NewQuery();
95
96 query.SetParameter("@Resource", "GarbageCollectorLock");
97 query.SetParameter("@LockMode", "Exclusive");
98 query.SetParameter("@LockOwner", "Session");
99 query.SetParameter("@LockTimeout", 0);
100
101 query.ExecuteSP("sp_getapplock", m_Timeout);
102 int status = query.GetStatus();
103
104 // status >= 0 => success
105 if (status < 0)
106 NCBI_THROW(CNetStorageGCException, eApplicationLockError,
107 "sp_getapplock return code: " +
108 NStr::NumericToString(status));
109 } catch (const exception & exc) {
110 cerr << "Error getting the application lock: " << exc.what() << endl;
111 throw;
112 } catch (...) {
113 cerr << "Unknown error getting the application lock "
114 "for the database" << endl;
115 throw;
116 }
117
118 if (m_Verbose)
119 cout << "Got" << endl;
120 }
121
122
ReleaseAppLock(void)123 void CNetStorageGCDatabase::ReleaseAppLock(void)
124 {
125 if (m_Verbose)
126 cout << "Releasing the application lock..." << endl;
127
128 try {
129 CQuery query = m_Db->NewQuery();
130
131 query.SetParameter("@Resource", "GarbageCollectorLock");
132 query.SetParameter("@LockOwner", "Session");
133
134 query.ExecuteSP("sp_releaseapplock", m_Timeout);
135 if (query.GetStatus() != 0)
136 NCBI_THROW(CNetStorageGCException, eApplicationLockError,
137 "Error releasing the application lock");
138 } catch (const CNetStorageGCException & ex) {
139 ERR_POST(ex);
140 cerr << ex.what() << endl;
141 return;
142 } catch (const CException & ex) {
143 ERR_POST(ex);
144 cerr << "Exception while releasing the application lock "
145 "for the database: " << ex.what() << endl;
146 return;
147 } catch (const std::exception & ex) {
148 ERR_POST(ex.what());
149 cerr << "Exception while releasing the application lock "
150 "for the database: " << ex.what() << endl;
151 return;
152 } catch (...) {
153 string msg = "Unknown error of releasing the application lock "
154 "for the database";
155 ERR_POST(msg);
156 cerr << msg << endl;
157 return;
158 }
159
160 if (m_Verbose)
161 cout << "Released" << endl;
162 }
163
164
x_ReadDbAccessInfo(const CNcbiRegistry & reg)165 void CNetStorageGCDatabase::x_ReadDbAccessInfo(const CNcbiRegistry & reg)
166 {
167 if (m_Verbose)
168 cout << "Reading the NetStorage meta info "
169 "database connection parameters..." << endl;
170 m_DbAccessInfo.m_Service = reg.GetString("database", "service", "");
171 m_DbAccessInfo.m_Database = reg.GetString("database", "database", "");
172 m_DbAccessInfo.m_UserName = reg.GetString("database", "user_name", "");
173 m_DbAccessInfo.m_Password = reg.GetEncryptedString(
174 "database", "password",
175 IRegistry::fPlaintextAllowed);
176
177 if (m_Verbose)
178 cout << "Read" << endl;
179 }
180
181
x_CreateDatabase(const CNcbiRegistry & reg)182 void CNetStorageGCDatabase::x_CreateDatabase(const CNcbiRegistry & reg)
183 {
184 x_ReadDbAccessInfo(reg);
185
186 string uri = "dbapi://" + m_DbAccessInfo.m_UserName +
187 ":" + m_DbAccessInfo.m_Password +
188 "@" + m_DbAccessInfo.m_Service +
189 "/" + m_DbAccessInfo.m_Database;
190
191 CSDB_ConnectionParam db_params(uri);
192
193 if (m_Verbose)
194 cout << "Creating CDatabase (uri: " << uri << ")..." << endl;
195 m_Db = new CDatabase(db_params);
196 if (m_Verbose)
197 cout << "Created" << endl;
198 }
199
200
201 vector<string>
GetGCCandidates(void)202 CNetStorageGCDatabase::GetGCCandidates(void)
203 {
204 vector<string> candidates;
205 string stmt = "SELECT object_loc FROM Objects "
206 "WHERE tm_expiration IS NOT NULL AND "
207 "tm_expiration < GETDATE()";
208
209 if (m_Verbose)
210 cout << "Retrieving the expired objects from the NetStorage meta info "
211 "database..." << endl;
212
213 try {
214 CQuery query = m_Db->NewQuery(stmt);
215 query.Execute(m_Timeout);
216
217 ITERATE(CQuery, row, query.SingleSet()) {
218 candidates.push_back(row["object_loc"].AsString());
219 }
220 } catch (...) {
221 cerr << "Error retrieving the expired objects from the NetStorage meta "
222 "info database" << endl;
223 throw;
224 }
225
226 if (m_Verbose)
227 cout << "Retrieved " << candidates.size()
228 << " expired object(s)" << endl;
229 return candidates;
230 }
231
232
233 int
GetDBStructureVersion(void)234 CNetStorageGCDatabase::GetDBStructureVersion(void)
235 {
236 string stmt = "SELECT version FROM Versions "
237 "WHERE name = 'db_structure'";
238 int db_ver = -1;
239
240 if (m_Verbose)
241 cout << "Retrieving the version of the NetStorage meta info "
242 "database structure..." << endl;
243
244 try {
245 CQuery query = m_Db->NewQuery(stmt);
246 query.Execute(m_Timeout);
247
248 ITERATE(CQuery, row, query.SingleSet()) {
249 if (db_ver != -1) {
250 string msg = "Too many NetStorage meta info "
251 "database structure versions";
252 cerr << msg << endl;
253 NCBI_THROW(CNetStorageGCException, eTooManyDBStructureVersions,
254 msg);
255 }
256 db_ver = row["version"].AsInt4();
257 }
258 } catch (const CNetStorageGCException & ex) {
259 throw;
260 } catch (...) {
261 cerr << "Error retrieving the version of the NetStorage meta info "
262 "database structure..." << endl;
263 throw;
264 }
265
266 if (db_ver == -1) {
267 string msg = "Cannot find the version of the NetStorage meta info "
268 "database structure";
269 cerr << msg << endl;
270 NCBI_THROW(CNetStorageGCException, eDBStructureVersionNotFound, msg);
271 }
272
273 if (m_Verbose)
274 cout << "Retrieved: " << db_ver << endl;
275 return db_ver;
276 }
277
278
279 void
RemoveObject(const string & locator,bool dryrun,const string & hit_id)280 CNetStorageGCDatabase::RemoveObject(const string & locator, bool dryrun,
281 const string & hit_id)
282 {
283 CRef<CRequestContext> ctx;
284
285 // It involves removing attributes and removing the object record
286 if (m_Verbose)
287 cout << "Removing attributes of object " << locator << endl;
288
289 string stmt = "DELETE FROM AttrValues WHERE object_id IN ("
290 "SELECT object_id FROM Objects WHERE object_loc='" +
291 locator + "')";
292
293 try {
294 CQuery query = m_Db->NewQuery(stmt);
295
296 ctx.Reset(new CRequestContext());
297 ctx->SetRequestID();
298 GetDiagContext().SetRequestContext(ctx);
299 ctx->SetHitID(hit_id);
300 GetDiagContext().PrintRequestStart()
301 .Print("action", "meta_attributes_remove")
302 .Print("locator", locator);
303
304 if (!dryrun)
305 query.Execute(m_Timeout);
306
307 ctx->SetRequestStatus(200);
308 GetDiagContext().PrintRequestStop();
309 ctx.Reset();
310 GetDiagContext().SetRequestContext(NULL);
311 } catch (const CException & ex) {
312 ERR_POST(ex);
313
314 ctx->SetRequestStatus(500);
315 GetDiagContext().PrintRequestStop();
316 ctx.Reset();
317 GetDiagContext().SetRequestContext(NULL);
318
319 cerr << "Exception while removing attributes of object "
320 << locator << endl;
321 NCBI_THROW(CNetStorageGCException, eStopGC, k_StopGC);
322 } catch (const std::exception & ex ) {
323 ERR_POST(ex.what());
324
325 ctx->SetRequestStatus(500);
326 GetDiagContext().PrintRequestStop();
327 ctx.Reset();
328 GetDiagContext().SetRequestContext(NULL);
329
330 cerr << "std::exception while removing attributes of object "
331 << locator << endl;
332 NCBI_THROW(CNetStorageGCException, eStopGC, k_StopGC);
333 } catch (...) {
334 ERR_POST(k_UnknownException);
335
336 ctx->SetRequestStatus(500);
337 GetDiagContext().PrintRequestStop();
338 ctx.Reset();
339 GetDiagContext().SetRequestContext(NULL);
340
341 cerr << "Unknown exception while removing attributes of object "
342 << locator << endl;
343 NCBI_THROW(CNetStorageGCException, eStopGC, k_StopGC);
344 }
345
346 // Second part: removing the object record
347 if (m_Verbose)
348 cout << "Removing the object record for " << locator << endl;
349
350 stmt = "DELETE FROM Objects WHERE object_loc='" + locator + "'";
351 try {
352 CQuery query = m_Db->NewQuery(stmt);
353
354 ctx.Reset(new CRequestContext());
355 ctx->SetRequestID();
356 GetDiagContext().SetRequestContext(ctx);
357 ctx->SetHitID(hit_id);
358 GetDiagContext().PrintRequestStart()
359 .Print("action", "meta_object_remove")
360 .Print("locator", locator);
361
362 if (!dryrun)
363 query.Execute(m_Timeout);
364
365 ctx->SetRequestStatus(200);
366 GetDiagContext().PrintRequestStop();
367 ctx.Reset();
368 GetDiagContext().SetRequestContext(NULL);
369 } catch (const CException & ex) {
370 ERR_POST(ex);
371
372 ctx->SetRequestStatus(500);
373 GetDiagContext().PrintRequestStop();
374 ctx.Reset();
375 GetDiagContext().SetRequestContext(NULL);
376
377 cerr << "Exception while removing the object record for "
378 << locator << endl;
379 NCBI_THROW(CNetStorageGCException, eStopGC, k_StopGC);
380 } catch (const std::exception & ex ) {
381 ERR_POST(ex.what());
382
383 ctx->SetRequestStatus(500);
384 GetDiagContext().PrintRequestStop();
385 ctx.Reset();
386 GetDiagContext().SetRequestContext(NULL);
387
388 cerr << "std::exception while removing the object record for "
389 << locator << endl;
390 NCBI_THROW(CNetStorageGCException, eStopGC, k_StopGC);
391 } catch (...) {
392 ERR_POST(k_UnknownException);
393
394 ctx->SetRequestStatus(500);
395 GetDiagContext().PrintRequestStop();
396 ctx.Reset();
397 GetDiagContext().SetRequestContext(NULL);
398
399 cerr << "Unknown exception while removing the object record for "
400 << locator << endl;
401 NCBI_THROW(CNetStorageGCException, eStopGC, k_StopGC);
402 }
403 }
404
405
406 END_NCBI_SCOPE
407
408