CUBRID Engine  latest
transaction_transient.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
20 
21 #include "es.h"
22 #include "heap_file.h"
23 #include "lob_locator.hpp"
24 #include "oid.h"
25 #include "memory_hash.h"
27 #include "rb_tree.h"
28 #include "string_buffer.hpp"
29 #include "vacuum.h"
30 
31 #include <cstring> // for std::strcpy
32 //
33 // TODO: Create a "transaction transient" abstract interface and split this into multiple files
34 //
35 
36 //
37 // Modified classes
38 //
39 
40 tx_transient_class_entry::tx_transient_class_entry (const char *class_name, const OID &class_oid, const LOG_LSA &lsa)
41  : m_class_oid (class_oid)
42  , m_last_modified_lsa (lsa)
43  , m_class_name (class_name)
44 {
45 }
46 
47 const char *
49 {
50  return m_class_name.c_str ();
51 }
52 
53 void
54 tx_transient_class_registry::add (const char *classname, const OID &class_oid, const LOG_LSA &lsa)
55 {
56  assert (classname != NULL);
57  assert (!OID_ISNULL (&class_oid));
58  assert (class_oid.volid >= 0); // is not temp volume
59 
60  for (auto &it : m_list)
61  {
62  if (it.m_class_name == classname && OID_EQ (&it.m_class_oid, &class_oid))
63  {
64  it.m_last_modified_lsa = lsa;
65  return;
66  }
67  }
68  m_list.emplace_front (classname, class_oid, lsa);
69 }
70 
71 bool
73 {
74  for (auto &it : m_list)
75  {
76  if (OID_EQ (&class_oid, &it.m_class_oid))
77  {
78  return true;
79  }
80  }
81  return false;
82 }
83 
84 char *
86 {
87  const size_t DEFAULT_STRBUF_SIZE = 128;
88  string_buffer strbuf (cubmem::PRIVATE_BLOCK_ALLOCATOR, DEFAULT_STRBUF_SIZE);
89 
90  strbuf ("{");
91  for (list_type::const_iterator it = m_list.cbegin (); it != m_list.cend (); it++)
92  {
93  if (it != m_list.cbegin ())
94  {
95  strbuf (", ");
96  }
97  strbuf ("name=%s, oid=%d|%d|%d, lsa=%lld|%d", it->m_class_name.c_str (), OID_AS_ARGS (&it->m_class_oid),
98  LSA_AS_ARGS (&it->m_last_modified_lsa));
99  }
100  strbuf ("}");
101  return strbuf.release_ptr ();
102 }
103 
104 void
106 {
107  bool stop = false;
108  for (const auto &it : m_list)
109  {
110  func (it, stop);
111  if (stop)
112  {
113  return;
114  }
115  }
116 }
117 
118 bool
120 {
121  return m_list.empty ();
122 }
123 
124 void
126 {
127  for (auto &it : m_list)
128  {
129  assert (!it.m_last_modified_lsa.is_null ());
130  if (downto_lsa.is_null () || it.m_last_modified_lsa > downto_lsa)
131  {
132  (void) heap_classrepr_decache (NULL, &it.m_class_oid);
133  }
134  }
135 }
136 
137 void
139 {
140  m_list.clear ();
141 }
142 
143 //
144 // Lobs
145 //
146 
148 {
153 };
154 
156 {
157  /* RB_ENTRY defines red-black tree node header for this structure. see base/rb_tree.h for more information. */
160  /* key_hash is used to reduce the number of strcmp. see the comment of lob_locator_cmp for more information */
161  int key_hash;
162  std::string m_key;
163 };
164 
165 static void lob_locator_put_meta (const char *locator, std::string &meta_name); // copy meta from locator
166 static void lob_locator_free (lob_locator_entry *&entry);
167 static int lob_locator_cmp (const lob_locator_entry *e1, const lob_locator_entry *e2);
168 /* RB_PROTOTYPE_STATIC declares red-black tree functions. see base/rb_tree.h */
170 
171 int
172 xtx_add_lob_locator (cubthread::entry *thread_p, const char *locator, LOB_LOCATOR_STATE state)
173 {
174  int tran_index;
175  LOG_TDES *tdes = NULL;
176  lob_locator_entry *entry = NULL;
177  lob_savepoint_entry *savept = NULL;
178 
179  assert (lob_locator_is_valid (locator));
180 
181  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
182  tdes = LOG_FIND_TDES (tran_index);
183  if (tdes == NULL)
184  {
187  }
188 
189  entry = new lob_locator_entry ();
190  savept = new lob_savepoint_entry ();
191 
192  entry->top = savept;
193  entry->m_key = lob_locator_key (locator);
194  entry->key_hash = (int) mht_5strhash (entry->m_key.c_str (), INT_MAX);
195 
196  savept->state = state;
197  savept->savept_lsa = LSA_LT (&tdes->savept_lsa, &tdes->topop_lsa) ? tdes->topop_lsa : tdes->savept_lsa;
198  savept->prev = NULL;
199  strlcpy (savept->locator, locator, sizeof (ES_URI));
200 
201  /* Insert entry to the red-black tree (see base/rb_tree.h) */
202  RB_INSERT (lob_rb_root, &tdes->lob_locator_root, entry);
203 
204  return NO_ERROR;
205 }
206 
208 xtx_find_lob_locator (cubthread::entry *thread_p, const char *locator, char *real_locator)
209 {
210  int tran_index;
211  LOG_TDES *tdes;
212 
213  assert (lob_locator_is_valid (locator));
214  assert (real_locator != NULL);
215 
216  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
217  tdes = LOG_FIND_TDES (tran_index);
218 
219  if (tdes != NULL)
220  {
221  lob_locator_entry *entry, find;
222 
223  find.m_key = lob_locator_key (locator);
224  find.key_hash = (int) mht_5strhash (find.m_key.c_str (), INT_MAX);
225  /* Find entry from red-black tree (see base/rb_tree.h) */
226  entry = RB_FIND (lob_rb_root, &tdes->lob_locator_root, &find);
227  if (entry != NULL)
228  {
229  std::strcpy (real_locator, entry->top->locator);
230  return entry->top->state;
231  }
232  }
233  else
234  {
235  // is this acceptable?
236  }
237 
238  std::strcpy (real_locator, locator);
239  return LOB_NOT_FOUND;
240 }
241 
242 int
243 xtx_change_state_of_locator (cubthread::entry *thread_p, const char *locator, const char *new_locator,
244  LOB_LOCATOR_STATE state)
245 {
246  int tran_index;
247  LOG_TDES *tdes;
248  lob_locator_entry *entry, find;
249 
250  assert (lob_locator_is_valid (locator));
251 
252  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
253  tdes = LOG_FIND_TDES (tran_index);
254  if (tdes == NULL)
255  {
258  }
259 
260  find.m_key = lob_locator_key (locator);
261  find.key_hash = (int) mht_5strhash (find.m_key.c_str (), INT_MAX);
262  entry = RB_FIND (lob_rb_root, &tdes->lob_locator_root, &find);
263 
264  if (entry != NULL)
265  {
266  LOG_LSA last_lsa;
267 
268  last_lsa = LSA_GE (&tdes->savept_lsa, &tdes->topop_lsa) ? tdes->savept_lsa : tdes->topop_lsa;
269 
270  /* if it is created prior to current savepoint, push the previous state in the savepoint list */
271  if (LSA_LT (&entry->top->savept_lsa, &last_lsa))
272  {
273  lob_savepoint_entry *savept = new lob_savepoint_entry ();
274 
275  /* copy structure (avoid redundant memory copy) */
276  savept->state = entry->top->state;
277  savept->savept_lsa = entry->top->savept_lsa;
278  std::strcpy (savept->locator, entry->top->locator);
279  savept->prev = entry->top;
280  entry->top = savept;
281  }
282 
283  /* set the current state */
284  if (new_locator != NULL)
285  {
286  strlcpy (entry->top->locator, new_locator, sizeof (ES_URI));
287  }
288  entry->top->state = state;
289  entry->top->savept_lsa = last_lsa;
290  }
291 
292  return NO_ERROR;
293 }
294 
295 /*
296  * xlog_drop_lob_locator -
297  *
298  * return: error code
299  *
300  * thread_p(in):
301  * locator(in):
302  *
303  * NOTE:
304  */
305 int
306 xtx_drop_lob_locator (cubthread::entry *thread_p, const char *locator)
307 {
308  int tran_index;
309  LOG_TDES *tdes;
310  lob_locator_entry *entry, find;
311 
312  assert (lob_locator_is_valid (locator));
313 
314  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
315  tdes = LOG_FIND_TDES (tran_index);
316  if (tdes == NULL)
317  {
320  }
321 
322  find.m_key = lob_locator_key (locator);
323  find.key_hash = (int) mht_5strhash (find.m_key.c_str (), INT_MAX);
324  /* Remove entry that matches 'find' entry from the red-black tree. see base/rb_tree.h for more information */
325  entry = RB_FIND (lob_rb_root, &tdes->lob_locator_root, &find);
326  if (entry != NULL)
327  {
328  entry = RB_REMOVE (lob_rb_root, &tdes->lob_locator_root, entry);
329  if (entry != NULL)
330  {
331  lob_locator_free (entry);
332  }
333  }
334 
335  return NO_ERROR;
336 }
337 
338 void
339 lob_locator_put_meta (const char *locator, std::string &meta_name)
340 {
341  const char *keyp = lob_locator_key (locator);
342  const char *metap = lob_locator_meta (locator);
343 
344  if (keyp - 1 <= metap)
345  {
346  assert (false);
347  return;
348  }
349  size_t diff = (size_t) (keyp - metap - 1);
350 
351  meta_name.append (metap, diff);
352  meta_name[diff] = '\0';
353 }
354 
355 static void
357 {
358  while (entry->top != NULL)
359  {
360  lob_savepoint_entry *savept;
361 
362  savept = entry->top;
363  entry->top = savept->prev;
364  delete savept;
365  }
366 
367  delete entry;
368  entry = NULL;
369 }
370 
371 void
372 tx_lob_locator_clear (cubthread::entry *thread_p, log_tdes *tdes, bool at_commit, LOG_LSA *savept_lsa)
373 {
374  lob_locator_entry *entry, *next;
375  bool need_to_delete;
376 
377  if (tdes == NULL)
378  {
379  return;
380  }
381 
382  for (entry = RB_MIN (lob_rb_root, &tdes->lob_locator_root); entry != NULL; entry = next)
383  {
384  /* setup next link before destroy */
385  next = RB_NEXT (lob_rb_root, &tdes->lob_locator_root, entry);
386 
387  need_to_delete = false;
388 
389  if (at_commit)
390  {
391  if (entry->top->state != LOB_PERMANENT_CREATED)
392  {
393  need_to_delete = true;
394  }
395  }
396  else /* rollback */
397  {
398  /* at partial rollback, pop the previous states in the savepoint list util it meets the rollback savepoint */
399  if (savept_lsa != NULL)
400  {
401  lob_savepoint_entry *savept, *tmp;
402 
403  assert (entry->top != NULL);
404  savept = entry->top->prev;
405 
406  while (savept != NULL)
407  {
408  if (LSA_LT (&entry->top->savept_lsa, savept_lsa))
409  {
410  break;
411  }
412 
413  /* rollback file renaming */
414  if (strcmp (entry->top->locator, savept->locator) != 0)
415  {
416  std::string meta_name;
417 
418  assert (lob_locator_is_valid (savept->locator));
419  lob_locator_put_meta (savept->locator, meta_name);
420  /* ignore return value */
421  (void) es_rename_file (entry->top->locator, meta_name.c_str (), savept->locator);
422  }
423  tmp = entry->top;
424  entry->top = savept;
425  savept = savept->prev;
426  delete tmp;
427  }
428  }
429 
430  /* delete the locator to be created */
431  if ((savept_lsa == NULL || LSA_GE (&entry->top->savept_lsa, savept_lsa))
432  && entry->top->state != LOB_TRANSIENT_DELETED)
433  {
434  need_to_delete = true;
435  }
436  }
437 
438  /* remove from the locator tree */
439  if (need_to_delete)
440  {
441 #if defined (SERVER_MODE)
442  if (at_commit && entry->top->state == LOB_PERMANENT_DELETED)
443  {
444  vacuum_notify_es_deleted (thread_p, entry->top->locator);
445  }
446  else
447  {
448  /* The file is created and rolled-back and it is not visible to anyone. Delete it directly without
449  * notifying vacuum. */
450  (void) es_delete_file (entry->top->locator);
451  }
452 #else /* !SERVER_MODE */
453  /* SA_MODE */
454  (void) es_delete_file (entry->top->locator);
455 #endif /* !SERVER_MODE */
456  RB_REMOVE (lob_rb_root, &tdes->lob_locator_root, entry);
457  lob_locator_free (entry);
458  }
459  }
460 
461  /* at the end of transaction, free the locator list */
462  if (savept_lsa == NULL)
463  {
464  for (entry = RB_MIN (lob_rb_root, &tdes->lob_locator_root); entry != NULL; entry = next)
465  {
466  next = RB_NEXT (lob_rb_root, &tdes->lob_locator_root, entry);
467  RB_REMOVE (lob_rb_root, &tdes->lob_locator_root, entry);
468  lob_locator_free (entry);
469  }
470  assert (RB_EMPTY (&tdes->lob_locator_root));
471  }
472 }
473 
474 static int
476 {
477  if (e1->key_hash != e2->key_hash)
478  {
479  return e1->key_hash - e2->key_hash;
480  }
481  else
482  {
483  return e1->m_key.compare (e2->m_key);
484  }
485 }
486 
487 /*
488  * Below macro generates lob rb tree functions (see base/rb_tree.h)
489  * Note: semi-colon is intentionally added to be more beautiful
490  */
492 
493 void
495 {
496  RB_INIT (this);
497 }
bool is_null() const
Definition: log_lsa.hpp:92
void tx_lob_locator_clear(cubthread::entry *thread_p, log_tdes *tdes, bool at_commit, LOG_LSA *savept_lsa)
#define NO_ERROR
Definition: error_code.h:46
struct lob_rb_root lob_locator_root
Definition: log_impl.h:516
void add(const char *classname, const OID &class_oid, const LOG_LSA &lsa)
ES_URI locator
#define RB_EMPTY(head)
Definition: rb_tree.h:63
#define RB_NEXT(name, x, y)
Definition: rb_tree.h:470
std::string m_class_name
LOG_LSA topop_lsa
Definition: log_impl.h:479
static void lob_locator_put_meta(const char *locator, std::string &meta_name)
std::function< void(const tx_transient_class_entry &, bool &)> map_func_type
LOG_TDES * LOG_FIND_TDES(int tran_index)
Definition: log_impl.h:1095
#define LSA_AS_ARGS(lsa_ptr)
Definition: log_lsa.hpp:78
#define diff
Definition: mprec.h:352
int xtx_add_lob_locator(cubthread::entry *thread_p, const char *locator, LOB_LOCATOR_STATE state)
const block_allocator PRIVATE_BLOCK_ALLOCATOR
#define OID_AS_ARGS(oidp)
Definition: oid.h:39
bool LSA_LT(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:174
tx_transient_class_entry()=default
bool has_class(const OID &class_oid) const
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
#define assert(x)
int xtx_drop_lob_locator(cubthread::entry *thread_p, const char *locator)
LOB_LOCATOR_STATE state
const char * get_classname() const
LOG_LSA savept_lsa
LOG_LSA savept_lsa
Definition: log_impl.h:478
int es_rename_file(const char *in_uri, const char *metaname, char *out_uri)
Definition: es.c:417
#define OID_EQ(oidp1, oidp2)
Definition: oid.h:92
bool lob_locator_is_valid(const char *locator)
Definition: lob_locator.cpp:37
RB_GENERATE_STATIC(lob_rb_root, lob_locator_entry, head, lob_locator_cmp)
#define NULL
Definition: freelistheap.h:34
int es_delete_file(const char *uri)
Definition: es.c:301
const char * lob_locator_key(const char *locator)
Definition: lob_locator.cpp:54
#define RB_FIND(name, x, y)
Definition: rb_tree.h:468
unsigned int mht_5strhash(const void *key, const unsigned int ht_size)
Definition: memory_hash.c:521
#define RB_REMOVE(name, x, y)
Definition: rb_tree.h:467
#define ER_LOG_UNKNOWN_TRANINDEX
Definition: error_code.h:913
static int lob_locator_cmp(const lob_locator_entry *e1, const lob_locator_entry *e2)
bool LSA_GE(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:181
lob_savepoint_entry * prev
int heap_classrepr_decache(THREAD_ENTRY *thread_p, const OID *class_oid)
Definition: heap_file.c:1818
int key_hash
#define LOG_FIND_THREAD_TRAN_INDEX(thrd)
Definition: perf_monitor.h:158
#define ARG_FILE_LINE
Definition: error_manager.h:44
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: porting.c:2584
lob_savepoint_entry * top
#define RB_INSERT(name, x, y)
Definition: rb_tree.h:466
RB_PROTOTYPE_STATIC(lob_rb_root, lob_locator_entry, head, lob_locator_cmp)
std::string m_key
char ES_URI[ES_MAX_URI_LEN]
Definition: es.h:35
enum lob_locator_state LOB_LOCATOR_STATE
Definition: lob_locator.hpp:62
void decache_heap_repr(const LOG_LSA &downto_lsa)
void map(const map_func_type &func) const
#define RB_INIT(root)
Definition: rb_tree.h:44
int xtx_change_state_of_locator(cubthread::entry *thread_p, const char *locator, const char *new_locator, LOB_LOCATOR_STATE state)
#define OID_ISNULL(oidp)
Definition: oid.h:81
#define RB_ENTRY(type)
Definition: rb_tree.h:50
static void lob_locator_free(lob_locator_entry *&entry)
#define RB_MIN(name, x)
Definition: rb_tree.h:472
LOB_LOCATOR_STATE xtx_find_lob_locator(cubthread::entry *thread_p, const char *locator, char *real_locator)
const char * lob_locator_meta(const char *locator)
Definition: lob_locator.cpp:60