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