NCBI C++ ToolKit
bdb_volumes.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: bdb_volumes.cpp 91509 2020-11-06 15:06:32Z grichenk $
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: Anatoliy Kuznetsov
27  *
28  * File Description: Volumes management
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 #include <corelib/ncbifile.hpp>
34 
35 #include <db/bdb/bdb_volumes.hpp>
36 #include <db/bdb/bdb_cursor.hpp>
37 #include <db/bdb/bdb_trans.hpp>
38 
39 #include <db/error_codes.hpp>
40 
41 
42 #define NCBI_USE_ERRCODE_X Db_Bdb_Volumes
43 
45 
46 /// Transaction class for volumes management
47 ///
48 /// @internal
50 {
51 public:
53  : CBDB_Transaction(*(volumes.m_Env),
55  {
56  volumes.m_VolumesDB->SetTransaction(this);
57  }
58 };
59 
60 
61 
62 
64 {
65 }
66 
68 {
69  try {
70  Close();
71  }
72  catch (std::exception& ex)
73  {
74  ERR_POST_X(1, "Exception in ~CBDB_Volumes() " << ex.what());
75  }
76 }
77 
79 {
80  m_VolumesDB.reset(0);
81  m_Env.reset(0);
82 }
83 
84 void CBDB_Volumes::Open(const string& dir_path)
85 {
86  Close();
88  // Make sure our directory exists
89  {{
90  CDir dir(m_Path);
91  if ( !dir.Exists() ) {
92  dir.Create();
93  }
94  }}
95  m_Env.reset(new CBDB_Env());
96  string err_file = m_Path + "err.log";
97  m_Env->OpenErrFile(err_file.c_str());
98  m_Env->SetLogFileMax(20 * 1024 * 1024);
99 
100  CDir dir(m_Path);
102  if (fl.empty()) {
103  m_Env->OpenWithTrans(m_Path, CBDB_Env::eThreaded);
104  } else {
105  try {
106  m_Env->JoinEnv(m_Path, CBDB_Env::eThreaded);
107  if (!m_Env->IsTransactional()) {
108  m_Env.reset(0);
109  NCBI_THROW(CBDB_VolumesException, eTransactionsNotAvailable,
110  "Joined non-transactional environment");
111  }
112  }
113  catch (CBDB_ErrnoException& err_ex)
114  {
115  if (err_ex.IsRecovery()) {
116  ERR_POST_X(2, Warning <<
117  "'Warning: DB_ENV returned DB_RUNRECOVERY code."
118  " Running the recovery procedure.");
119  }
120  m_Env->OpenWithTrans(m_Path,
122  }
123  catch (CBDB_Exception&)
124  {
125  m_Env->OpenWithTrans(m_Path,
127  }
128  }
129  //m_Env->SetDirectDB(true);
130  //m_Env->SetDirectLog(true);
131  m_Env->SetLogAutoRemove(true);
132 
133  m_Env->SetLockTimeout(30 * 1000000); // 30 sec
134 
135  m_VolumesDB.reset(new SVolumesDB());
136  m_VolumesDB->SetEnv(*m_Env);
137  m_VolumesDB->Open("volumes.db", CBDB_RawFile::eReadWriteCreate);
138 }
139 
140 const SVolumesDB& CBDB_Volumes::FetchVolumeRec(unsigned volume_id)
141 {
142  m_VolumesDB->volume_id = volume_id;
143  EBDB_ErrCode err = m_VolumesDB->Fetch();
144  if (err != eBDB_Ok) {
145  NCBI_THROW(CBDB_VolumesException, eVolumeNotFound,
146  string("Cannot find volume=") + NStr::UIntToString(volume_id));
147  }
148  return *m_VolumesDB;
149 }
150 
151 unsigned CBDB_Volumes::AddVolume(const string& location,
152  unsigned type,
153  unsigned version,
154  EVolumeStatus status)
155 {
156  m_VolumesDB->type = type;
157  m_VolumesDB->status = status;
158  m_VolumesDB->raw_status = 0;
159  m_VolumesDB->lock = 0;
160  m_VolumesDB->version = version;
161  m_VolumesDB->date_from = 0;
162  m_VolumesDB->date_to = 0;
163  m_VolumesDB->mtimestamp = (Uint4)time(0);
164  m_VolumesDB->relo_volume_id = 0;
165  m_VolumesDB->location = location;
166  m_VolumesDB->backup_loc = "";
167 
168  CBDB_VolumesTransaction trans(*this);
169  unsigned volume_id = m_VolumesDB->Append();
170  trans.Commit();
171 
172  return volume_id;
173 }
174 
176 
177 
178  /// retrieve the enumerated volumes and store them in a sorted map
179  vector<unsigned> vol_ids;
180  typedef map<string, unsigned> TSortedVols;
181  TSortedVols sorted_volumes;
182 
183  EnumerateVolumes(vol_ids);
184 
185  ITERATE (vector<unsigned>, iter, vol_ids) {
186  const SVolumesDB& db = FetchVolumeRec(*iter);
187  string path = (string)db.location;
188  sorted_volumes.insert(TSortedVols::value_type(path, *iter));
189  }
190 
191  CBDB_VolumesTransaction trans(*this);
192 
193  ITERATE (TSortedVols, iter, sorted_volumes) {
194  m_VolumesDB->volume_id = iter->second;
195  EBDB_ErrCode err = m_VolumesDB->Fetch();
196  if (err != eBDB_Ok) {
197  NCBI_THROW(CBDB_VolumesException, eVolumeNotFound,
198  string("Cannot find volume=") + NStr::UIntToString(iter->second));
199  }
200  m_VolumesDB->Append();
201  }
202  trans.Commit();
203 
204  Delete(vol_ids);
205 }
206 
207 void CBDB_Volumes::SetBackupLocation(unsigned volume_id,
208  const string& backup_loc)
209 {
210  CBDB_VolumesTransaction trans(*this);
211  m_VolumesDB->volume_id = volume_id;
212  EBDB_ErrCode err = m_VolumesDB->FetchForUpdate();
213  if (err != eBDB_Ok) {
214  NCBI_THROW(CBDB_VolumesException, eVolumeNotFound,
215  string("Cannot find volume=") + NStr::UIntToString(volume_id));
216  }
217  m_VolumesDB->backup_loc = backup_loc;
218  m_VolumesDB->UpdateInsert();
219  trans.Commit();
220 }
221 
222 void CBDB_Volumes::LockVolume(unsigned volume_id)
223 {
224  CBDB_VolumesTransaction trans(*this);
225  m_VolumesDB->volume_id = volume_id;
226  EBDB_ErrCode err = m_VolumesDB->FetchForUpdate();
227  if (err != eBDB_Ok) {
228  NCBI_THROW(CBDB_VolumesException, eVolumeNotFound,
229  string("Cannot find volume=") + NStr::UIntToString(volume_id));
230  }
231  unsigned lock = m_VolumesDB->lock;
232 
233  m_VolumesDB->lock = ++lock;
234  m_VolumesDB->UpdateInsert();
235  trans.Commit();
236 }
237 
238 void CBDB_Volumes::Delete(const vector<unsigned>& remove_list)
239 {
240  CBDB_VolumesTransaction trans(*this);
241 
242  for (vector<unsigned>::const_iterator iter = remove_list.begin();
243  iter != remove_list.end(); ++iter) {
244  m_VolumesDB->volume_id = *iter;
245  EBDB_ErrCode err = m_VolumesDB->FetchForUpdate();
246  if (err != eBDB_Ok) {
247  NCBI_THROW(CBDB_VolumesException, eVolumeNotFound,
248  string("Cannot find volume=") + NStr::UIntToString(*iter));
249  }
250  m_VolumesDB->Delete();
251  }
252 
253  trans.Commit();
254 }
255 
256 void CBDB_Volumes::UnLockVolume(unsigned volume_id)
257 {
258  CBDB_VolumesTransaction trans(*this);
259  m_VolumesDB->volume_id = volume_id;
260  EBDB_ErrCode err = m_VolumesDB->FetchForUpdate();
261  if (err != eBDB_Ok) {
262  NCBI_THROW(CBDB_VolumesException, eVolumeNotFound,
263  string("Cannot find volume=") + NStr::UIntToString(volume_id));
264  }
265  unsigned lock = m_VolumesDB->lock;
266  if (lock == 0) {
267  NCBI_THROW(CBDB_VolumesException, eVolumeNotLocked,
268  string("Cannot unlock (lock count == 0) volume=")
269  + NStr::UIntToString(volume_id));
270  }
271 
272  m_VolumesDB->lock = ++lock;
273  m_VolumesDB->UpdateInsert();
274  trans.Commit();
275 
276 }
277 
278 
279 void CBDB_Volumes::ChangeStatus(unsigned volume_id, EVolumeStatus status)
280 {
281  CBDB_VolumesTransaction trans(*this);
282 
283  x_ChangeCurrentStatus(volume_id, status);
284 
285  trans.Commit();
286 }
287 
288 void CBDB_Volumes::SwitchVolumes(unsigned volume_id_old,
289  unsigned volume_id_new,
290  EVolumeStatus new_status)
291 {
292  CBDB_VolumesTransaction trans(*this);
293 
294  x_ChangeCurrentStatus(volume_id_old, eOffline);
295  x_ChangeCurrentStatus(volume_id_new, new_status);
296 
297  trans.Commit();
298 }
299 
300 void CBDB_Volumes::Split(unsigned volume_id_old,
301  unsigned volume_id_new1,
302  unsigned volume_id_new2,
303  EVolumeStatus new_status)
304 {
305  CBDB_VolumesTransaction trans(*this);
306 
307  x_ChangeCurrentStatus(volume_id_old, eOffline);
308  x_ChangeCurrentStatus(volume_id_new1, new_status);
309  x_ChangeCurrentStatus(volume_id_new2, new_status);
310 
311  trans.Commit();
312 }
313 
314 void CBDB_Volumes::Merge(unsigned volume_id_new,
315  const vector<unsigned>& merge_list,
316  EVolumeStatus new_status)
317 {
318  CBDB_VolumesTransaction trans(*this);
319 
320  x_ChangeCurrentStatus(volume_id_new, new_status);
321 
322  Delete(merge_list);
323 
324  trans.Commit();
325 }
326 
327 void CBDB_Volumes::EnumerateVolumes(vector<unsigned>& vlist, bool avail)
328 {
329  vlist.resize(0);
331  while (cur.Fetch() == eBDB_Ok) {
332  unsigned volume_id = m_VolumesDB->volume_id;
333  if (avail) {
334  EVolumeStatus status =
335  (EVolumeStatus)(unsigned)m_VolumesDB->status;
336  switch (status) {
337  case eOnlinePassive:
338  case eOnlineActive:
339  case eOnlineMaintenance:
340  break;
341  default:
342  continue;
343  } // switch
344  }
345  vlist.push_back(volume_id);
346  }
347 }
348 
350 {
351  return *m_VolumesDB;
352 }
353 
354 void CBDB_Volumes::SetDateRange(unsigned volume_id,
355  unsigned from,
356  unsigned to)
357 {
358  CBDB_VolumesTransaction trans(*this);
359  m_VolumesDB->volume_id = volume_id;
360  EBDB_ErrCode err = m_VolumesDB->FetchForUpdate();
361  if (err != eBDB_Ok) {
362  NCBI_THROW(CBDB_VolumesException, eVolumeNotFound,
363  string("Cannot find volume=") + NStr::UIntToString(volume_id));
364  }
365  unsigned lock = m_VolumesDB->lock;
366  if (lock == 0) {
367  NCBI_THROW(CBDB_VolumesException, eVolumeNotLocked,
368  string("Cannot unlock (lock count == 0) volume=")
369  + NStr::UIntToString(volume_id));
370  }
371  m_VolumesDB->date_from = from;
372  m_VolumesDB->date_to = to;
373 
374  m_VolumesDB->UpdateInsert();
375  trans.Commit();
376 }
377 
378 
379 void CBDB_Volumes::x_ChangeCurrentStatus(unsigned volume_id,
380  EVolumeStatus status)
381 {
382  m_VolumesDB->volume_id = volume_id;
383  EBDB_ErrCode err = m_VolumesDB->FetchForUpdate();
384  if (err != eBDB_Ok) {
385  NCBI_THROW(CBDB_VolumesException, eVolumeNotFound,
386  string("Cannot find volume=") + NStr::UIntToString(volume_id));
387  }
388  unsigned lock = m_VolumesDB->lock;
389  if (lock) {
390  NCBI_THROW(CBDB_VolumesException, eVolumeLocked,
391  string("Volume locked volume=") + NStr::UIntToString(volume_id));
392  }
393  EVolumeStatus old_status = (EVolumeStatus)(unsigned)m_VolumesDB->status;
394  bool can_do = x_CheckStatusChange(old_status, status);
395  if (!can_do) {
396  NCBI_THROW(CBDB_VolumesException, eVolumeStatusIncorrect,
397  string("Illegal volume status switch volume=")
398  + NStr::UIntToString(volume_id)
399  + string(" old status = ") + StatusToString(old_status)
400  + string(" new status = ") + StatusToString(status)
401  );
402  }
403  m_VolumesDB->status = (unsigned)status;
404  m_VolumesDB->UpdateInsert();
405 
406 }
407 
408 
410 {
411  switch (status)
412  {
413  case eOnlinePassive: return "OnlinePassive";
414  case eOnlineActive: return "OnlineActive";
415  case eOnlineMaintenance: return "OnlineMaintenance";
416  case eOffline: return "Offline";
417  case eOfflineRelocated: return "OfflineRelocated";
418  case eOfflineArchived: return "OfflineArchived";
419  case eOfflineRestore: return "OfflineRestore";
420  default:
421  _ASSERT(0);
422  return "Unknown status";
423  } // switch
424 }
425 
426 
428  EVolumeStatus new_status)
429 {
430  if (new_status == old_status) return true;
431 
432  // FSM rules are hard coded here...
433 
434  switch (new_status)
435  {
436  case eOnlinePassive:
437  switch (old_status)
438  {
439  case eOnlineActive:
440  case eOnlineMaintenance:
441  case eOffline:
442  case eOfflineArchived:
443  case eOfflineRestore:
444  return true;
445  default:
446  break;
447  } // switch
448  break;
449  case eOnlineActive:
450  switch (old_status)
451  {
452  case eOnlinePassive:
453  case eOnlineMaintenance:
454  case eOffline:
455  case eOfflineRestore:
456  return true;
457  default:
458  break;
459  } // switch
460  break;
461  case eOnlineMaintenance:
462  switch (old_status)
463  {
464  case eOnlinePassive:
465  case eOnlineActive:
466  case eOffline:
467  case eOfflineRestore:
468  return true;
469  default:
470  break;
471  } // switch
472  break;
473  case eOffline:
474  switch (old_status)
475  {
476  case eOnlinePassive:
477  case eOnlineActive:
478  case eOnlineMaintenance:
479  case eOfflineRelocated:
480  case eOfflineArchived:
481  case eOfflineRestore:
482  return true;
483  default:
484  break;
485  } // switch
486  break;
487  case eOfflineRelocated:
488  switch (old_status)
489  {
490  case eOnlinePassive:
491  case eOnlineActive:
492  case eOnlineMaintenance:
493  case eOffline:
494  case eOfflineRelocated:
495  case eOfflineArchived:
496  case eOfflineRestore:
497  return true;
498  default:
499  break;
500  } // switch
501  break;
502  case eOfflineArchived:
503  switch (old_status)
504  {
505  case eOnlinePassive:
506  case eOffline:
507  case eOfflineRestore:
508  return true;
509  default:
510  _ASSERT(0);
511  } // switch
512  break;
513  case eOfflineRestore:
514  switch (old_status)
515  {
516  case eOfflineArchived:
517  return true;
518  default:
519  break;
520  } // switch
521  break;
522  default:
523  break;
524  } // switch
525  return false;
526 }
527 
528 
529 
531 
532 
Berkeley BDB file cursor.
Wrapper around Berkeley DB transaction structure.
BDB environment object a collection including support for some or all of caching, locking,...
Definition: bdb_env.hpp:61
BDB errno exception class.
Definition: bdb_expt.hpp:84
Base BDB exception class.
Definition: bdb_expt.hpp:53
Berkeley DB file cursor class.
Definition: bdb_cursor.hpp:95
BDB transaction object.
Definition: bdb_trans.hpp:63
Exceptions specific to volumes management.
Transaction class for volumes management.
Definition: bdb_volumes.cpp:50
CBDB_VolumesTransaction(CBDB_Volumes &volumes)
Definition: bdb_volumes.cpp:52
Volumes management.
Definition: bdb_volumes.hpp:97
void LockVolume(unsigned volume_id)
Increment volume lock counter Volume locking sets restrictions on some operations (like status change...
void Merge(unsigned volume_id_new, const vector< unsigned > &merge_list, EVolumeStatus new_status=eOnlineActive)
Merge volumes into one.
unsigned AddVolume(const string &location, unsigned type, unsigned version, EVolumeStatus status=eOffline)
Register a new volume.
void Delete(const vector< unsigned > &remove_list)
Delete volume.
void Open(const string &dir_path)
Open (mount) volume management database.
Definition: bdb_volumes.cpp:84
void SwitchVolumes(unsigned volume_id_old, unsigned volume_id_new, EVolumeStatus new_status=eOnlineActive)
Transactional volume switch: old volume goes offline new volume comes online.
void SetDateRange(unsigned volume_id, unsigned from, unsigned to)
Update date range.
void ChangeStatus(unsigned volume_id, EVolumeStatus status)
Change volume status.
void Close()
Close volume management database.
Definition: bdb_volumes.cpp:78
void SetBackupLocation(unsigned volume_id, const string &backup_loc)
Set backup token (location) for volume.
void EnumerateVolumes(vector< unsigned > &vlist, bool avail=false)
Get list of all available volumes.
bool x_CheckStatusChange(EVolumeStatus old_status, EVolumeStatus new_status)
Check if status change is possible.
const SVolumesDB & FetchVolumeRec(unsigned volume_id)
Get volume record (throws an exception if record not found)
void Split(unsigned volume_id_old, unsigned volume_id_new1, unsigned volume_id_new2, EVolumeStatus new_status=eOnlineActive)
Old volume goes offline, new volumes online All volume records should be created upfront.
unique_ptr< CBDB_Env > m_Env
SVolumesDB & GetVolumeDB()
Get low level access to volumes database (be careful will you!)
void SortVolumes()
Sort volumes.
void x_ChangeCurrentStatus(unsigned volume_id, EVolumeStatus status)
void UnLockVolume(unsigned volume_id)
Decrement volume lock counter.
EVolumeStatus
Volume status codes.
@ eOnlineMaintenance
Online, readable, under background processing.
@ eOnlineActive
Online, new updates can come.
@ eOfflineRestore
Offline, restore request received.
@ eOffline
Offline, unmounted.
@ eOfflineRelocated
Offline, data moved to another volume.
@ eOfflineArchived
Offline, data moved to archive.
@ eOnlinePassive
Online, read-only closed for updates.
static string StatusToString(EVolumeStatus status)
Utility to convert status to string.
unique_ptr< SVolumesDB > m_VolumesDB
CDir –.
Definition: ncbifile.hpp:1695
static const char location[]
Definition: config.c:97
static int type
Definition: getdata.c:31
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
EBDB_ErrCode
BDB Return codes.
Definition: bdb_file.hpp:57
EBDB_ErrCode Fetch(EFetchDirection fdir=eDefault)
Fetch record.
Definition: bdb_cursor.cpp:665
@ eReadWriteCreate
read-write, create if it doesn't exist
Definition: bdb_file.hpp:82
@ eBDB_Ok
Definition: bdb_file.hpp:58
virtual void Commit()
Commit transaction.
Definition: bdb_trans.cpp:74
bool IsRecovery() const
If it is DB_RUNRECOVERY error.
Definition: bdb_expt.cpp:81
CBDB_Env & m_Env
Associated environment.
Definition: bdb_trans.hpp:164
@ eTransSync
Syncronous transaction.
Definition: bdb_trans.hpp:69
@ eRunRecovery
Run DB recovery first.
Definition: bdb_env.hpp:65
@ eThreaded
corresponds to DB_THREAD
Definition: bdb_env.hpp:64
string
Definition: cgiapp.hpp:687
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
Definition: ncbidiag.hpp:550
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
void Warning(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1191
TEntries GetEntries(const string &mask=kEmptyStr, TGetEntriesFlags flags=0) const
Get directory entries based on the specified "mask".
Definition: ncbifile.cpp:3846
static string AddTrailingPathSeparator(const string &path)
Add trailing path separator, if needed.
Definition: ncbifile.cpp:455
virtual bool Exists(void) const
Check if directory "dirname" exists.
Definition: ncbifile.hpp:4065
bool Create(TCreateFlags flags=fCreate_Default) const
Create the directory using "dirname" passed in the constructor.
Definition: ncbifile.cpp:4071
list< TEntry > TEntries
Definition: ncbifile.hpp:1750
@ eIgnoreRecursive
Definition: ncbifile.hpp:1774
uint32_t Uint4
4-byte (32-bit) unsigned integer
Definition: ncbitype.h:103
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
static string UIntToString(unsigned int value, TNumToStringFlags flags=0, int base=10)
Convert UInt to string.
Definition: ncbistr.hpp:5108
Definition of all error codes used in bdb library (bdb.lib and ncbi_xcache_bdb.lib).
static int version
Definition: mdb_load.c:29
double value_type
The numeric datatype used by the parser.
Definition: muParserDef.h:228
Defines classes: CDirEntry, CFile, CDir, CSymLink, CMemoryFile, CFileUtil, CFileLock,...
BDB file for storing volumes registry.
Definition: bdb_volumes.hpp:47
CBDB_FieldString location
Mount point for the volume.
Definition: bdb_volumes.hpp:59
Definition: type.c:6
#define _ASSERT
Modified on Mon Dec 11 02:38:23 2023 by modify_doxy.py rev. 669887