CUBRID Engine  latest
locator_cl.c
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 
19 /*
20  * locator_cl.c - Transaction object locator (at client)
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <assert.h>
29 #include <signal.h>
30 
31 #include "authenticate.h"
32 #include "db.h"
33 #include "environment_variable.h"
34 #include "porting.h"
35 #include "locator_cl.h"
36 #include "memory_alloc.h"
37 #include "storage_common.h"
38 #include "work_space.h"
39 #include "object_representation.h"
40 #include "transform_cl.h"
41 #include "class_object.h"
42 #include "schema_manager.h"
43 #include "server_interface.h"
44 #include "locator.h"
45 #include "boot_cl.h"
46 #include "virtual_object.h"
47 #include "memory_hash.h"
48 #include "system_parameter.h"
49 #include "dbi.h"
50 #include "replication.h"
51 #include "transaction_cl.h"
52 #include "network_interface_cl.h"
53 #include "execute_statement.h"
54 #include "log_lsa.hpp"
55 
56 #define WS_SET_FOUND_DELETED(mop) WS_SET_DELETED(mop)
57 #define MAX_FETCH_SIZE 64
58 
59 /* Mflush structures */
62 { /* Keep temporarily OIDs when flushing */
63  MOP mop; /* Mop with temporarily OID */
64  int obj; /* The mflush object number */
66 };
67 
70 { /* Description of mflushing block structure */
71  LC_COPYAREA *copy_area; /* Area where mflush objects are placed */
72  LC_COPYAREA_MANYOBJS *mobjs; /* Structure which describes mflush objects */
73  LC_COPYAREA_ONEOBJ *obj; /* Describe one object */
74  LOCATOR_MFLUSH_TEMP_OID *mop_toids; /* List of objects with temp. OIDs */
75  LOCATOR_MFLUSH_TEMP_OID *mop_uoids; /* List of object which we're updating in a partitioned class. We have to keep
76  * track of this because they might return with a different class and we have
77  * to mark them accordingly */
80  MOP class_mop; /* Class_mop of last mflush object */
81  MOBJ class_obj; /* The class of last mflush object */
82  HFID *hfid; /* Instance heap of last mflush obj */
83  RECDES recdes; /* Record descriptor */
84  bool decache; /* true, if objects are decached after they are mflushed. */
85  bool isone_mflush; /* true, if we are not doing a massive flushing of objects */
86 };
87 
90 {
91  OID *oid; /* Fetched object */
92  OID *class_oid; /* Class of object */
93  TRAN_ISOLATION isolation; /* Client isolation level */
94  LOCK lock; /* Lock acquired for fetched object */
95  LOCK class_lock; /* Lock acquired for class */
96  LOCK implicit_lock; /* Lock acquired for prefetched objects */
97  LC_FETCH_VERSION_TYPE fetch_version_type; /* version type to fetch */
98 };
99 
102 {
103  LIST_MOPS *list; /* The nested list of mops */
104 };
105 
108 {
109  int (*fun) (MOBJ class_obj); /* Function to call to decide if this a class that it is kept */
110  LOCK lock; /* The lock to cache */
111  LIST_MOPS *list; /* The list of mops */
112 };
113 
114 static volatile sig_atomic_t lc_Is_siginterrupt = false;
115 
116 #if defined(CUBRID_DEBUG)
117 static void locator_dump_mflush (FILE * out_fp, LOCATOR_MFLUSH_CACHE * mflush);
118 #endif /* CUBRID_DEBUG */
119 static void locator_cache_lock (MOP mop, MOBJ ignore_notgiven_object, void *xcache_lock);
120 static void locator_cache_lock_set (MOP mop, MOBJ ignore_notgiven_object, void *xlockset);
121 static LOCK locator_to_prefetched_lock (LOCK class_lock);
122 static int locator_lock (MOP mop, LC_OBJTYPE isclass, LOCK lock, LC_FETCH_VERSION_TYPE fetch_version_type);
123 static int locator_lock_class_of_instance (MOP inst_mop, MOP * class_mop, LOCK lock);
124 static int locator_lock_and_doesexist (MOP mop, LOCK lock, LC_OBJTYPE isclass);
125 static int locator_lock_set (int num_mops, MOP * vector_mop, LOCK reqobj_inst_lock, LOCK reqobj_class_lock,
126  int quit_on_errors);
127 static int locator_set_chn_classes_objects (LC_LOCKSET * lockset);
128 static int locator_get_rest_objects_classes (LC_LOCKSET * lockset, MOP class_mop, MOBJ class_obj);
129 static int locator_lock_nested (MOP mop, LOCK lock, int prune_level, int quit_on_errors,
130  int (*fun) (LC_LOCKSET * req, void *args), void *args);
131 static int locator_decache_lock (MOP mop, void *ignore);
132 static int locator_cache_object_class (MOP mop, LC_COPYAREA_ONEOBJ * obj, MOBJ * object_p, RECDES * recdes_p,
133  bool * call_fun);
134 static int locator_cache_object_instance (MOP mop, MOP class_mop, MOP * hint_class_mop_p, MOBJ * hint_class_p,
135  LC_COPYAREA_ONEOBJ * obj, MOBJ * object_p, RECDES * recdes_p,
136  bool * call_fun);
137 static int locator_cache_not_have_object (MOP * mop_p, MOBJ * object_p, bool * call_fun, LC_COPYAREA_ONEOBJ * obj);
138 static int locator_cache_have_object (MOP * mop_p, MOBJ * object_p, RECDES * recdes_p, MOP * hint_class_mop_p,
139  MOBJ * hint_class_p, bool * call_fun, LC_COPYAREA_ONEOBJ * obj);
140 static int locator_cache (LC_COPYAREA * copy_area, MOP hint_class_mop, MOBJ hint_class,
141  void (*fun) (MOP mop, MOBJ object, void *args), void *args);
142 static LC_FIND_CLASSNAME locator_find_class_by_name (const char *classname, LOCK lock, MOP * class_mop);
143 static int locator_mflush (MOP mop, void *mf);
144 static int locator_mflush_initialize (LOCATOR_MFLUSH_CACHE * mflush, MOP class_mop, MOBJ clazz, HFID * hfid,
145  bool decache, bool isone_mflush);
146 static void locator_mflush_reset (LOCATOR_MFLUSH_CACHE * mflush);
147 static int locator_mflush_reallocate_copy_area (LOCATOR_MFLUSH_CACHE * mflush, int minsize);
148 
149 static int locator_repl_mflush (LOCATOR_MFLUSH_CACHE * mflush);
150 static int locator_repl_mflush_force (LOCATOR_MFLUSH_CACHE * mflush);
151 static void locator_repl_mflush_check_error (LC_COPYAREA * mflush);
152 
153 static void locator_mflush_end (LOCATOR_MFLUSH_CACHE * mflush);
154 static int locator_mflush_force (LOCATOR_MFLUSH_CACHE * mflush);
155 static int locator_class_to_disk (LOCATOR_MFLUSH_CACHE * mflush, MOBJ object, bool * has_index, int *round_length_p,
156  WS_MAP_STATUS * map_status);
157 static int locator_mem_to_disk (LOCATOR_MFLUSH_CACHE * mflush, MOBJ object, bool * has_index, int *round_length_p,
158  WS_MAP_STATUS * map_status);
159 static void locator_mflush_set_dirty (MOP mop, MOBJ ignore_object, void *ignore_argument);
160 static void locator_keep_mops (MOP mop, MOBJ object, void *kmops);
161 static int locator_instance_decache (MOP mop, void *ignore);
162 static int locator_save_nested_mops (LC_LOCKSET * lockset, void *save_mops);
163 static LC_FIND_CLASSNAME locator_find_class_by_oid (MOP * class_mop, const char *classname, OID * class_oid, LOCK lock);
164 static LIST_MOPS *locator_fun_get_all_mops (MOP class_mop, DB_FETCH_MODE purpose, int (*fun) (MOBJ class_obj),
165  LC_FETCH_VERSION_TYPE * force_fetch_version_type);
166 static int locator_internal_flush_instance (MOP inst_mop, bool decache);
167 
168 static int locator_add_to_oidset_when_temp_oid (MOP mop, void *data);
169 
170 static bool locator_can_skip_fetch_from_server (MOP mop, LOCK * lock, LC_FETCH_VERSION_TYPE fetch_version_type);
171 
172 /*
173  * locator_reserve_class_name () -
174  * return:
175  * class_name(in):
176  * class_oid(in):
177  */
179 locator_reserve_class_name (const char *class_name, OID * class_oid)
180 {
181  return locator_reserve_class_names (1, &class_name, class_oid);
182 }
183 
184 /*
185  * locator_set_sig_interrupt () -
186  *
187  * return:
188  * set(in):
189  *
190  * Note:
191  */
192 void
194 {
195  if (set != 0 || lc_Is_siginterrupt != 0)
196  {
197  lc_Is_siginterrupt = set;
198  log_set_interrupt (set);
199  }
200 
201 }
202 
203 /*
204  * locator_is_root () - Is mop the root mop?
205  *
206  * return:
207  * mop(in): Memory Object pointer
208  *
209  * Note: Find out if the passed mop is the root mop.
210  */
211 bool
213 {
214  if (mop == sm_Root_class_mop || ws_mop_compare (mop, sm_Root_class_mop) == 0)
215  {
216  return true;
217  }
218  else
219  {
220  return false;
221  }
222 }
223 
224 /*
225  * locator_is_class () - Is mop a class mop?
226  *
227  * return: < 0 - error, == 0 is not a class, > 0 - is a class
228  *
229  * mop(in): Memory Object pointer
230  * hint_purpose(in): Fetch purpose: Valid ones for this function
231  * DB_FETCH_READ
232  * DB_FETCH_WRITE
233  *
234  * Note: Find out if the object associated with the given mop is a
235  * class object. If the object does not exist, the function
236  * returns that the object is not a class.
237  */
238 int
239 locator_is_class (MOP mop, DB_FETCH_MODE hint_purpose)
240 {
241  MOP class_mop;
242 
243  if (!mop || WS_ISVID (mop))
244  {
245  return 0;
246  }
247 
248  class_mop = ws_class_mop (mop);
249  if (class_mop == NULL)
250  {
251  int error = NO_ERROR;
252  MOBJ obj = NULL;
253  bool error_saved = false;
254 
255  if (er_errid () != NO_ERROR)
256  {
257  er_stack_push ();
258  error_saved = true;
259  }
260  /*
261  * The class identifier of the object associated with the mop is stored
262  * along with the object on the disk representation. The class mop is not
263  * stored with the object since the object is not cached, fetch the object
264  * and cache it into the workspace
265  */
266  obj = locator_fetch_object (mop, hint_purpose, TM_TRAN_READ_FETCH_VERSION ());
267  error = er_errid ();
268  if (error_saved)
269  {
270  if (error == NO_ERROR)
271  {
272  er_stack_pop ();
273  }
274  else
275  {
277  }
278  }
279  if (error != NO_ERROR)
280  {
281  return error;
282  }
283 
284  if (obj == NULL)
285  {
286  return 0; /* Object does not exist, so it is not a class */
287  }
288  class_mop = ws_class_mop (mop);
289  }
290 
291  return (locator_is_root (class_mop) ? 1 : 0);
292 }
293 
294 /*
295  * locator_cache_lock () -
296  *
297  * return: nothing
298  *
299  * mop(in): Memory Object pointer
300  * ignore_notgiven_object(in): The object is not passed... ignored
301  * xcache_lock(in): The lock to cache
302  *
303  * Note: Cache the lock for the given object MOP. The cached lock type
304  * is included in the cache_lock structure, and it depends upon
305  * the object that is passed.. that is, the requested object, the
306  * class of the requested object, or a prefetched object.
307  */
308 static void
309 locator_cache_lock (MOP mop, MOBJ ignore_notgiven_object, void *xcache_lock)
310 {
311  LOCATOR_CACHE_LOCK *cache_lock;
312  OID *oid;
313  MOP class_mop;
314  LOCK lock;
315  LC_FETCH_VERSION_TYPE fetch_version_type = LC_FETCH_MVCC_VERSION;
316 
317  cache_lock = (LOCATOR_CACHE_LOCK *) xcache_lock;
318  oid = ws_oid (mop);
319 
320  /*
321  * The cached lock depends upon the object that we are dealing, Is the
322  * object the requested one, is the class of the requested object,
323  * or is a prefetched object
324  */
325 
326  if (OID_EQ (oid, cache_lock->oid))
327  {
328  lock = cache_lock->lock;
329  fetch_version_type = cache_lock->fetch_version_type;
330  }
331  else if (cache_lock->class_oid && OID_EQ (oid, cache_lock->class_oid))
332  {
333  lock = cache_lock->class_lock;
334  }
335  else
336  {
337  assert (cache_lock->implicit_lock >= NULL_LOCK && ws_get_lock (mop) >= NULL_LOCK);
338  lock = lock_Conv[cache_lock->implicit_lock][ws_get_lock (mop)];
339  assert (lock != NA_LOCK);
340  }
341 
342  /*
343  * If the lock is IS_LOCK, IX_LOCK, the object must be a class. Otherwise,
344  * we call the server with the wrong lock, the server should have fixed
345  * the lock by now.
346  */
347 
348  class_mop = ws_class_mop (mop);
349 
350  if (class_mop != NULL && class_mop != sm_Root_class_mop)
351  {
352  /*
353  * An instance
354  */
355  if (lock > NULL_LOCK)
356  {
357  if (lock == IS_LOCK)
358  {
359  /* fix read lock on client */
360  lock = S_LOCK;
361  }
362  else if (lock == IX_LOCK)
363  {
364  /* fix write lock on client */
365  lock = X_LOCK;
366  }
367 
368  if (lock == S_LOCK)
369  {
370  if (!LC_FETCH_IS_DIRTY_VERSION_NEEDED (fetch_version_type))
371  {
372  /* MVCC does not use shared locks on instances except when need last dirty version (fetch instance
373  * for update - will be updated later in current command) */
374  lock = NULL_LOCK;
375  }
376  }
377  }
378 
380  }
381 
382  ws_set_lock (mop, lock);
383 }
384 
385 /* Lock for prefetched instances of the same class */
386 static LOCK
388 {
389  if (class_lock == S_LOCK || class_lock == SIX_LOCK)
390  {
391  return S_LOCK;
392  }
393  else if (IS_WRITE_EXCLUSIVE_LOCK (class_lock))
394  {
395  return X_LOCK;
396  }
397  else
398  {
399  return NULL_LOCK;
400  }
401 }
402 
403 /*
404  * locator_cache_lock_set () - Cache a lock for the fetched object
405  *
406  * return: nothing
407  *
408  * mop(in): Memory Object pointer
409  * ignore_notgiven_object(in): The object is not passed... ignored
410  * xlockset(in): Request structure of requested objects to lock
411  * and fetch
412  *
413  * Note: Cache the lock for the given object MOP. The lock mode cached
414  * depends if the object is part of the requested object, part of
415  * the classes of the requested objects, or a prefetched object.
416  */
417 static void
418 locator_cache_lock_set (MOP mop, MOBJ ignore_notgiven_object, void *xlockset)
419 {
420  LC_LOCKSET *lockset; /* The area of requested objects */
421  OID *oid; /* Oid of the object being cached */
422  MOP class_mop; /* The class mop of the object being cached */
423  LOCK lock = NULL_LOCK; /* Lock to be set on the object being cached */
424  bool found = false;
425  int stopidx_class;
426  int stopidx_reqobj;
427  int i;
428 
429  lockset = (LC_LOCKSET *) xlockset;
430  if (lockset->reqobj_inst_lock == NULL_LOCK)
431  {
432  return;
433  }
434 
435  oid = ws_oid (mop);
436  class_mop = ws_class_mop (mop);
437 
438  stopidx_class = lockset->num_classes_of_reqobjs;
439  stopidx_reqobj = lockset->num_reqobjs;
440 
441  while (true)
442  {
443  /*
444  * Is the object part of the classes of the requested objects ?
445  */
446  for (i = lockset->last_classof_reqobjs_cached + 1; i < stopidx_class; i++)
447  {
448  if (OID_EQ (oid, &lockset->classes[i].oid))
449  {
450  /* The object was requested */
451  if (lockset->reqobj_inst_lock <= S_LOCK)
452  {
453  lock = IS_LOCK;
454  }
455  else
456  {
457  lock = IX_LOCK;
458  }
459 
460  assert (ws_get_lock (mop) >= NULL_LOCK);
461  lock = lock_Conv[lock][ws_get_lock (mop)];
462  assert (lock != NA_LOCK);
463  found = true;
464  /*
465  * Cache the location of the current on for future initialization of
466  * the search. The objects are cached in the same order as they are
467  * requested. The classes of the requested objects are sent before
468  * the actual requested objects
469  */
470  lockset->last_classof_reqobjs_cached = i;
471  break;
472  }
473  }
474 
475  /*
476  * Is the object part of the requested objects ?
477  */
478  for (i = lockset->last_reqobj_cached + 1; found == false && i < stopidx_reqobj; i++)
479  {
480  if (OID_EQ (oid, &lockset->objects[i].oid))
481  {
482  /* The object was requested */
483  /* Is the object a class ?.. */
484  if (class_mop != NULL && locator_is_root (class_mop))
485  {
486  lock = lockset->reqobj_class_lock;
487  }
488  else
489  {
490  lock = lockset->reqobj_inst_lock;
491  if (lock <= S_LOCK)
492  {
493  /* Object instances are not locked for read in MVCC */
494  lock = NULL_LOCK;
496  }
497  }
498 
499  assert (lock >= NULL_LOCK && ws_get_lock (mop) >= NULL_LOCK);
500  lock = lock_Conv[lock][ws_get_lock (mop)];
501  assert (lock != NA_LOCK);
502  found = true;
503  lockset->last_reqobj_cached = i;
504  /*
505  * Likely, we have finished all the classes by now.
506  */
508  break;
509  }
510  }
511 
512  /*
513  * If were not able to find the object. We need to start looking from
514  * the very beginning of the lists, and stop the searching one object
515  * before where the current search stopped.
516  *
517  * If we have already search both lists from the very beginning stop.
518  */
519 
520  if (found == true)
521  {
522  break;
523  }
524 
525  if (lockset->last_classof_reqobjs_cached != -1 || lockset->last_reqobj_cached != -1)
526  {
527  /*
528  * Try the portion of the list that we have not looked
529  */
530  stopidx_class = lockset->last_classof_reqobjs_cached - 1;
531  stopidx_reqobj = lockset->last_reqobj_cached - 1;
532 
533  lockset->last_classof_reqobjs_cached = -1;
534  lockset->last_reqobj_cached = -1;
535  }
536  else
537  {
538  /*
539  * Leave the hints the way they were..
540  */
541  lockset->last_classof_reqobjs_cached = stopidx_class + 1;
542  lockset->last_reqobj_cached = stopidx_reqobj;
543  break;
544  }
545  } /* while */
546 
547  if (found == false && class_mop != NULL)
548  {
549  /*
550  * This is a prefetched object
551  */
552  lock = ws_get_lock (class_mop);
553  lock = locator_to_prefetched_lock (lock);
554 
555  assert (lock >= NULL_LOCK && ws_get_lock (mop) >= NULL_LOCK);
556  lock = lock_Conv[lock][ws_get_lock (mop)];
557  assert (lock != NA_LOCK);
558 
559  /*
560  * If a prefetch a class somehow.. I don't have any lock on the root
561  * set, the lowest lock on it
562  */
563  if (lock == NULL_LOCK && class_mop == sm_Root_class_mop)
564  {
565  lock = IS_LOCK;
566  }
567  found = true;
568  }
569 
570  if (found == true)
571  {
572  // TODO: NULL_LOCK for inst locks on non-mvcc table??
573  ws_set_lock (mop, lock);
574  }
575 }
576 
577 /*
578  * locator_lock () - Lock an object
579  *
580  * return: NO_ERROR if all OK, ER status otherwise
581  *
582  * mop(in): Mop of the object to lock
583  * isclass(in): LC_OBJTYPE of mop to be locked
584  * lock(in): Lock to acquire
585  * fetch_version_type(in): fetch version type
586  *
587  * Note: The object associated with the given MOP is locked with the
588  * desired lock. The object locator on the server is not invoked
589  * if the object is actually cached with the desired lock or with
590  * a more powerful lock. In any other case, the object locator in
591  * the server is invoked to acquire the desired lock and possibly
592  * to bring the desired object along with some other objects that
593  * may be pre-fetched.
594  */
595 static int
596 locator_lock (MOP mop, LC_OBJTYPE isclass, LOCK lock, LC_FETCH_VERSION_TYPE fetch_version_type)
597 {
598  LOCATOR_CACHE_LOCK cache_lock; /* Cache the lock */
599  OID *oid; /* OID of object to lock */
600  int chn; /* Cache coherency number of object */
601  MOBJ object; /* The desired object */
602  MOP class_mop; /* Class mop of object to lock */
603  OID *class_oid; /* Class identifier of object to lock */
604  int class_chn; /* Cache coherency number of class of object to lock */
605  MOBJ class_obj; /* The class of the desired object */
606  LC_COPYAREA *fetch_area; /* Area where objects are received */
607  int error_code = NO_ERROR;
608  bool is_prefetch;
609  LOCK class_lock;
610 
611  oid = ws_oid (mop);
612 
613  if (WS_ISVID (mop))
614  {
615  /*
616  * Don't know how to fetch virtual object. This looks like a system error
617  * of the caller
618  */
619 #if defined(CUBRID_DEBUG)
620  er_log_debug (ARG_FILE_LINE, "locator_lock: ** SYSTEM ERROR don't know how to fetch virtual objects.");
622 #endif /* CUBRID_DEBUG */
623  /* if this gets occurs in a production system, we want to guard against a crash & have the same test results as
624  * the debug system. */
625  error_code = ER_FAILED;
626  goto end;
627  }
628 
629  if (ws_find (mop, &object) == WS_FIND_MOP_DELETED)
630  {
631  /* The object has been deleted */
632  if (do_Trigger_involved == false)
633  {
635  }
636  error_code = ER_FAILED;
637  goto end;
638  }
639 
640  /*
641  * Invoke the transaction object locator on the server either:
642  * a) if the object is not cached
643  * b) the current lock acquired on the object is less powerful
644  * than the requested lock.
645  */
646 
647  class_mop = ws_class_mop (mop);
648 
649  if (locator_can_skip_fetch_from_server (mop, &lock, fetch_version_type))
650  {
651  /* No need to fetch object from server */
652  goto end;
653  }
654 
655  /* We must invoke the transaction object locator on the server */
656  assert (lock != NA_LOCK);
657 
658  cache_lock.oid = oid;
659  cache_lock.lock = lock;
660  cache_lock.isolation = TM_TRAN_ISOLATION ();
661  if (ws_get_lock (mop) != NULL_LOCK)
662  {
663 #if 0
664  /* Normally, use current version since the object was already locked. However, for safety reason when promote
665  * S_LOCK to X_LOCK is better to use dirty version. This is needed to protect against wrong cached S-locks on
666  * client (the server release S-lock and the S-lock is not decached on client side). */
667  if (lock == X_LOCK && ws_get_lock (mop) == S_LOCK && isclass == LC_INSTANCE)
668 #else
669  if (isclass == LC_INSTANCE)
670 #endif
671  {
672  fetch_version_type = LC_FETCH_DIRTY_VERSION;
673  }
674  else if (isclass == LC_CLASS)
675  {
676  fetch_version_type = LC_FETCH_CURRENT_VERSION;
677  }
678  }
679  else if (class_mop != NULL)
680  {
681  class_lock = ws_get_lock (class_mop);
682  /*
683  * Since shared or exclusive class lock is requested, the purpose is to
684  * update class or instances (we do not allow such locks at select).
685  * In read committed, using MVCC version may lead to issues. Thus, we may
686  * select deleted objects (still visible for the current transaction)
687  * and later (same command) we may try to update already deleted object.
688  * In read committed, when class share or exclusive lock is requested,
689  * we can fetch dirty version of the instances. These instance versions
690  * are updatable instance versions for the current command. Also, these
691  * instance versions are visible versions for the next command of the
692  * transaction.
693  * In RR and SERIALIZABLE, we have to use MVCC version. Otherwise, we
694  * may update an instance that's not visible for current transaction,
695  * instead of returning SERIALIZABLE conflict (snapshot is acquired
696  * once / transaction).
697  */
698  if ((class_lock == S_LOCK || class_lock >= SIX_LOCK) && (TM_TRAN_ISOLATION () == TRAN_READ_COMMITTED))
699  {
700  fetch_version_type = LC_FETCH_DIRTY_VERSION;
701  }
702  }
703 
704  cache_lock.fetch_version_type = fetch_version_type;
705 
706  /* Find the cache coherency numbers for fetching purposes */
707  if (object == NULL && WS_IS_DELETED (mop))
708  {
710  error_code = ER_FAILED;
711  goto end;
712  }
713 
714  chn = ws_chn (object);
715  if (chn > NULL_CHN && isclass != LC_CLASS && sm_is_reuse_oid_class (mop))
716  {
717  /* Since an already cached object of a reuse_oid table may be deleted after it is cached to my workspace and
718  * then another object may occupy its slot, unfortunately the cached CHN has no meaning. When the new object
719  * occasionally has the same CHN with that of the cached object and we don't fetch the object from server again,
720  * * we will incorrectly reuse the cached deleted object. We need to refetch the cached object if it is an
721  * instance of reuse_oid table. Server will fetch the object since client passes NULL_CHN. */
722  chn = NULL_CHN;
723  }
724 
725  /*
726  * Get the class information for the desired object, just in case we need
727  * to bring it from the server.
728  */
729 
730  if (class_mop == NULL)
731  {
732  /* Don't know the class. Server must figure it out */
733  class_oid = NULL;
734  class_obj = NULL;
735  class_chn = NULL_CHN;
736  cache_lock.class_oid = class_oid;
737  cache_lock.class_lock = NULL_LOCK;
738  cache_lock.implicit_lock = NULL_LOCK;
739  }
740  else
741  {
742  class_oid = ws_oid (class_mop);
743  if (ws_find (class_mop, &class_obj) == WS_FIND_MOP_DELETED)
744  {
746  oid->slotid);
747  error_code = ER_FAILED;
748  goto end;
749  }
750  class_chn = ws_chn (class_obj);
751  cache_lock.class_oid = class_oid;
752  if (lock == NULL_LOCK)
753  {
754  cache_lock.class_lock = ws_get_lock (class_mop);
755  }
756  else
757  {
758  cache_lock.class_lock = (lock <= S_LOCK) ? IS_LOCK : IX_LOCK;
759 
760  assert (ws_get_lock (class_mop) >= NULL_LOCK);
761  cache_lock.class_lock = lock_Conv[cache_lock.class_lock][ws_get_lock (class_mop)];
762  assert (cache_lock.class_lock != NA_LOCK);
763  }
764 
765  /* Lock for prefetched instances of the same class */
766  cache_lock.implicit_lock = locator_to_prefetched_lock (cache_lock.class_lock);
767  }
768 
769  /* Now acquire the lock and fetch the object if needed */
770  if (cache_lock.implicit_lock != NULL_LOCK)
771  {
772  is_prefetch = true;
773  }
774  else
775  {
776  is_prefetch = false;
777  }
778 
780  {
781  /* The purpose was to fetch current version from beginning (not based on mop). This may happen when write results
782  * to stream. Converts LC_FETCH_CURRENT_VERSION to LC_FETCH_CURRENT_VERSION_NO_CHECK to avoid checks on server
783  * side. */
784  fetch_version_type = LC_FETCH_CURRENT_VERSION_NO_CHECK;
785  }
786 
787  if (locator_fetch (oid, chn, lock, fetch_version_type, class_oid, class_chn, is_prefetch, &fetch_area) != NO_ERROR)
788  {
789  error_code = ER_FAILED;
790  goto error;
791  }
792  /* We were able to acquire the lock. Was the cached object valid ? */
793 
794  if (fetch_area != NULL)
795  {
796  /*
797  * Cache the objects that were brought from the server
798  */
799  error_code = locator_cache (fetch_area, class_mop, class_obj, locator_cache_lock, &cache_lock);
800  locator_free_copy_area (fetch_area);
801  if (error_code != NO_ERROR)
802  {
803  goto error;
804  }
805  }
806 
807  /*
808  * Cache the lock for the object and its class.
809  * We need to do this since we don't know if the object was received in
810  * the fetch area
811  */
812  locator_cache_lock (mop, NULL, &cache_lock);
813 
814  if (class_mop != NULL)
815  {
816  locator_cache_lock (class_mop, NULL, &cache_lock);
817  }
818 
819 end:
820  return error_code;
821 
822 error:
823  /* There was a failure. Was the transaction aborted ? */
825  {
826  tran_abort_only_client (false);
827  }
828  else if (er_errid () == ER_HEAP_UNKNOWN_OBJECT)
829  {
830  /* Deleted object. */
831  WS_SET_DELETED (mop);
832  ws_decache (mop);
833  }
834 
835  return error_code;
836 }
837 
838 /*
839  * locator_lock_set () - Lock a set of objects
840  *
841  * return: NO_ERROR if all OK, ER status otherwise
842  *
843  * num_mops(in): Number of mops to lock
844  * vector_mop(in): A vector of mops to lock
845  * reqobj_inst_lock(in): Lock to acquire for requested objects that are
846  * instances.
847  * reqobj_class_lock(in): Lock to acquire for requested objects that are
848  classes
849  * quit_on_errors(in): Quit when an error is found such as cannot lock all
850  * nested objects.
851  *
852  * Note: The objects associated with the MOPs in the given vector_mop
853  * area are locked with the desired lock. The object locator on
854  * the server is not invoked if all objects are actually cached
855  * with the desired lock or with a more powerful lock. In any
856  * other case, the object locator in the server is invoked to
857  * acquire the desired lock and possibly to bring the desired
858  * objects along with some other objects that may be prefetched
859  * such as the classes of the objects.
860  * The function does not quit when an error is found if the value
861  * of request->quit_on_errors is false. In this case the
862  * object with the error is not locked/fetched. The function
863  * tries to lock all the objects at once, however if this fails
864  * and the function is allowed to continue when errors are
865  * detected, the objects are locked individually.
866  */
867 static int
868 locator_lock_set (int num_mops, MOP * vector_mop, LOCK reqobj_inst_lock, LOCK reqobj_class_lock, int quit_on_errors)
869 {
870  LC_LOCKSET *lockset; /* Area to object to be requested */
871  LC_LOCKSET_REQOBJ *reqobjs; /* Description of requested objects */
872  LC_LOCKSET_CLASSOF *reqclasses; /* Description of classes of requested objects */
873  MOP mop; /* mop of the object in question */
874  OID *oid; /* OID of MOP object to lock */
875  LOCK lock; /* The desired lock */
876  LOCK current_lock; /* Current lock cached for desired object */
877  MOBJ object; /* The desired object */
878  MOP class_mop = NULL; /* Class mop of object to lock */
879  OID *class_oid; /* Class id of object to lock */
880  MOBJ class_obj = NULL; /* The class of the desired object */
881  int error_code = NO_ERROR;
882  int i, j;
883  MHT_TABLE *htbl = NULL; /* Hash table of already found oids */
884 
885  if (num_mops <= 0)
886  {
887  return NO_ERROR;
888  }
889 
890  lockset = locator_allocate_lockset (num_mops, reqobj_inst_lock, reqobj_class_lock, quit_on_errors);
891  if (lockset == NULL)
892  {
893  /* Out of space... Try single object */
894  return locator_lock (vector_mop[0], LC_INSTANCE, reqobj_inst_lock, TM_TRAN_READ_FETCH_VERSION ());
895  }
896 
897  reqobjs = lockset->objects;
898  reqclasses = lockset->classes;
899 
900  /*
901  * If there were requested more than 30 objects, set a memory hash table
902  * to check for duplicates.
903  */
904 
905  if (num_mops > 30)
906  {
907  htbl = mht_create ("Memory hash locator_lock_set", num_mops, oid_hash, oid_compare_equals);
908  }
909 
910  for (i = 0; i < num_mops; i++)
911  {
912  mop = vector_mop[i];
913  if (mop == NULL)
914  {
915  continue;
916  }
917  class_mop = ws_class_mop (mop);
918  oid = ws_oid (mop);
919 
920  if (WS_ISVID (mop))
921  {
922  MOP temp;
923  /* get its real instance */
924  temp = db_real_instance (vector_mop[i]);
925  if (temp && !WS_ISVID (temp))
926  {
927  mop = temp;
928  class_mop = ws_class_mop (mop);
929  oid = ws_oid (mop);
930  }
931  }
932 
933  /*
934  * Make sure that it is not duplicated. This is needed since our API does
935  * not enforce uniqueness in sequences and so on.
936  *
937  * We may need to sort the list to speed up, removal of duplications or
938  * build a special kind of hash table.
939  */
940 
941  if (htbl != NULL)
942  {
943  /*
944  * Check for duplicates by looking into the hash table
945  */
946  if (mht_get (htbl, oid) == NULL)
947  {
948  /*
949  * The object has not been processed
950  */
951  if (mht_put (htbl, oid, mop) != mop)
952  {
953  mht_destroy (htbl);
954  htbl = NULL;
955  }
956  j = lockset->num_reqobjs;
957  }
958  else
959  {
960  /*
961  * These object has been processed. The object is duplicated in the
962  * list of requested objects.
963  */
964  j = 0;
965  }
966  }
967  else
968  {
969  /*
970  * We do not have a hash table to check for duplicates, we must do a
971  * sequential scan.
972  */
973  for (j = 0; j < lockset->num_reqobjs; j++)
974  {
975  if (OID_EQ (oid, &lockset->objects[j].oid))
976  {
977  break; /* The object is already in the request list */
978  }
979  }
980  }
981 
982  if (j < lockset->num_reqobjs)
983  {
984  continue;
985  }
986 
987  /* Is mop a class ? ... simple comparison, don't use locator_is_root */
988  if (class_mop == sm_Root_class_mop)
989  {
990  lock = reqobj_class_lock;
991  }
992  else
993  {
994  lock = reqobj_inst_lock;
995  }
996 
997  if (ws_find (mop, &object) == WS_FIND_MOP_DELETED)
998  {
999  if (quit_on_errors == false)
1000  {
1001  continue;
1002  }
1003  else
1004  {
1005  /* The object has been deleted */
1007  oid->slotid);
1008  error_code = ER_HEAP_UNKNOWN_OBJECT;
1009  break;
1010  }
1011  }
1012 
1013 #if defined (SA_MODE) && !defined (CUBRID_DEBUG)
1014  if (object != NULL)
1015  {
1016  /* The object is cached */
1017  assert (lock >= NULL_LOCK && ws_get_lock (class_mop) >= NULL_LOCK);
1018  lock = lock_Conv[lock][ws_get_lock (mop)];
1019  assert (lock != NA_LOCK);
1020  ws_set_lock (mop, lock);
1021  continue;
1022  }
1023 #endif /* SA_MODE && !CUBRID_DEBUG */
1024 
1025  /*
1026  * Invoke the transaction object locator on the server either:
1027  * a) if the object is not cached
1028  * b) the current lock acquired on the object is less powerful
1029  * than the requested lock.
1030  */
1031 
1032  current_lock = ws_get_lock (mop);
1033  assert (lock >= NULL_LOCK && current_lock >= NULL_LOCK);
1034  lock = lock_Conv[lock][current_lock];
1035  assert (lock != NA_LOCK);
1036 
1038  {
1039  continue;
1040  }
1041 
1042  /*
1043  * We must invoke the transaction object locator on the server for this
1044  * object.
1045  */
1046 
1047  /* Find the cache coherency numbers for fetching purposes */
1048  if (object == NULL && WS_IS_DELETED (mop))
1049  {
1050  /* Isn't this a duplicate check of ws_find == WS_FIND_MOP_DELETED? */
1051  if (quit_on_errors == false)
1052  {
1053  continue;
1054  }
1055  else
1056  {
1057  /* The object has been deleted */
1059  oid->slotid);
1060  error_code = ER_HEAP_UNKNOWN_OBJECT;
1061  break;
1062  }
1063  }
1064 
1065  COPY_OID (&reqobjs->oid, oid);
1066  reqobjs->chn = ws_chn (object);
1067 
1068  if (reqobjs->chn > NULL_CHN && sm_is_reuse_oid_class (mop))
1069  {
1070  /* Since an already cached object of a reuse_oid table may be deleted after it is cached to my workspace and
1071  * then another object may occupy its slot, unfortunately the cached CHN has no meaning. When the new object
1072  * occasionally has the same CHN with that of the cached object and we don't fetch the object from server
1073  * again, we will incorrectly reuse the cached deleted object. We need to refetch the cached object if it is
1074  * an instance of reuse_oid table. Server will fetch the object since client passes NULL_CHN. */
1075  reqobjs->chn = NULL_CHN;
1076  }
1077 
1078  /*
1079  * Get the class information for the desired object, just in case we
1080  * need to bring it from the server.
1081  */
1082 
1083  if (class_mop == NULL)
1084  {
1085  /* Don't know the class. Server must figure it out */
1086  reqobjs->class_index = -1;
1087  }
1088  else
1089  {
1090  class_oid = ws_oid (class_mop);
1091  if (ws_find (class_mop, &class_obj) == WS_FIND_MOP_DELETED)
1092  {
1093  if (quit_on_errors == false)
1094  {
1095  continue;
1096  }
1097  else
1098  {
1099  /* The class has been deleted */
1101  oid->pageid, oid->slotid);
1102  error_code = ER_HEAP_UNKNOWN_CLASS_OF_INSTANCE;
1103  break;
1104  }
1105  }
1106 
1107  COPY_OID (&reqclasses->oid, class_oid);
1108  reqclasses->chn = ws_chn (class_obj);
1109 
1110  /* Check for duplication in list of classes of requested objects */
1111  for (j = 0; j < lockset->num_classes_of_reqobjs; j++)
1112  {
1113  if (OID_EQ (class_oid, &lockset->classes[j].oid))
1114  {
1115  break; /* The class is already in the class array */
1116  }
1117  }
1118 
1119  if (j >= lockset->num_classes_of_reqobjs)
1120  {
1121  /* Class is not in the list */
1122  reqobjs->class_index = lockset->num_classes_of_reqobjs;
1123  lockset->num_classes_of_reqobjs++;
1124  reqclasses++;
1125  }
1126  else
1127  {
1128  /* Class is already in the list */
1129  reqobjs->class_index = j;
1130  }
1131  }
1132  lockset->num_reqobjs++;
1133  reqobjs++;
1134  }
1135 
1136  /*
1137  * We do not need the hash table any longer
1138  */
1139  if (htbl != NULL)
1140  {
1141  mht_destroy (htbl);
1142  htbl = NULL;
1143  }
1144 
1145  /*
1146  * Now acquire the locks and fetch the desired objects when needed
1147  */
1148 
1149  if (error_code == NO_ERROR && lockset != NULL && lockset->num_reqobjs > 0)
1150  {
1151  error_code = locator_get_rest_objects_classes (lockset, class_mop, class_obj);
1152  if (error_code == NO_ERROR)
1153  {
1154  /*
1155  * Cache the lock for the requested objects and their classes.
1156  */
1157  for (i = 0; i < lockset->num_classes_of_reqobjs; i++)
1158  {
1159  if ((!OID_ISNULL (&lockset->classes[i].oid))
1160  && (mop = ws_mop (&lockset->classes[i].oid, sm_Root_class_mop)) != NULL)
1161  {
1162  /*
1163  * The following statement was added as safety after the C/S stub
1164  * optimization of locator_fetch_lockset...which does not bring back
1165  * the lock lockset array
1166  */
1167  if (ws_find (mop, &object) != WS_FIND_MOP_DELETED && object != NULL)
1168  {
1169  locator_cache_lock_set (mop, NULL, lockset);
1170  }
1171  }
1172  else if (er_errid () == ER_OUT_OF_VIRTUAL_MEMORY)
1173  {
1174  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
1175  }
1176  }
1177 
1178  if (error_code == NO_ERROR)
1179  {
1180  for (i = 0; i < lockset->num_reqobjs; i++)
1181  {
1182  if ((!OID_ISNULL (&lockset->objects[i].oid))
1183  && (mop = ws_mop (&lockset->objects[i].oid, NULL)) != NULL)
1184  {
1185  /*
1186  * The following statement was added as safety after the
1187  * C/S stub optimization of locator_fetch_lockset...which does
1188  * not bring back the lock lockset array
1189  */
1190  if (ws_find (mop, &object) != WS_FIND_MOP_DELETED && object != NULL)
1191  {
1192  locator_cache_lock_set (mop, NULL, lockset);
1193  }
1194  }
1195  else if (er_errid () == ER_OUT_OF_VIRTUAL_MEMORY)
1196  {
1197  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
1198  }
1199  }
1200  }
1201  }
1202 
1203  if (quit_on_errors == false)
1204  {
1205  /* Make sure that there was not an error in the interested object */
1206  mop = vector_mop[0];
1207  if (ws_find (mop, &object) == WS_FIND_MOP_DELETED)
1208  {
1209  /* The object has been deleted */
1210  oid = ws_oid (mop);
1212  oid->slotid);
1213  error_code = ER_HEAP_UNKNOWN_OBJECT;
1214  goto error;
1215  }
1216  /* The only way to find out if there was an error, is by looking to acquired lock */
1217  class_mop = ws_class_mop (mop);
1218  if (class_mop == sm_Root_class_mop)
1219  {
1220  lock = reqobj_class_lock;
1221  }
1222  else
1223  {
1224  lock = reqobj_inst_lock;
1225  }
1226 
1227  current_lock = ws_get_lock (mop);
1228  assert (lock >= NULL_LOCK && current_lock >= NULL_LOCK);
1229  lock = lock_Conv[lock][current_lock];
1230  assert (lock != NA_LOCK);
1231 
1232  /* Object instances are not locked for read in MVCC */
1233  if ((class_mop == sm_Root_class_mop || lock > S_LOCK) && (current_lock == NULL_LOCK || lock != current_lock))
1234  {
1235  error_code = ER_FAILED;
1236  if (er_errid () == 0)
1237  {
1238  oid = ws_oid (mop);
1240  oid->slotid);
1241  error_code = ER_LC_LOCK_CACHE_ERROR;
1242  goto error;
1243  }
1244  }
1245  }
1246  }
1247 
1248 error:
1249  if (lockset != NULL)
1250  {
1251  locator_free_lockset (lockset);
1252  }
1253 
1254  return error_code;
1255 }
1256 
1257 /*
1258  * locator_set_chn_classes_objects:
1259  *
1260  * return : error code
1261  *
1262  * lockset(in/out):
1263  *
1264  * Note : Rest the cache coherence numbers to avoid receiving objects (classes
1265  * and instances) with the right state in the workspace.
1266  * We could have started with the number of classes/objects processed,
1267  * however, we start from zero to set to NULL_OID any object/class that
1268  * is deleted in the workspace.
1269  */
1270 static int
1272 {
1273  int i;
1274  MOP xmop; /* Temporarily mop area */
1275  MOBJ object; /* The desired object */
1276  OID *class_oid; /* Class identifier of object to lock */
1277 
1278  /*
1279  * First the classes of the object and its references
1280  */
1281 
1282  for (i = 0; i < lockset->num_classes_of_reqobjs; i++)
1283  {
1284  if (!OID_ISNULL (&lockset->classes[i].oid))
1285  {
1286  xmop = ws_mop (&lockset->classes[i].oid, sm_Root_class_mop);
1287  if (xmop == NULL || ws_find (xmop, &object) == WS_FIND_MOP_DELETED)
1288  {
1289  OID_SET_NULL (&lockset->classes[i].oid);
1290  }
1291  else
1292  {
1293  lockset->classes[i].chn = ws_chn (object);
1294  }
1295  }
1296  }
1297 
1298  /* Then the instances */
1299  for (i = 0; i < lockset->num_reqobjs; i++)
1300  {
1301  if (!OID_ISNULL (&lockset->objects[i].oid) && lockset->objects[i].class_index != -1)
1302  {
1303  class_oid = &lockset->classes[lockset->objects[i].class_index].oid;
1304  /* Make sure the neither the class or the object are deleted */
1305  if (OID_ISNULL (class_oid) || (xmop = ws_mop (&lockset->objects[i].oid, NULL)) == NULL
1306  || ws_find (xmop, &object) == WS_FIND_MOP_DELETED
1307  || (xmop = ws_mop (class_oid, sm_Root_class_mop)) == NULL || WS_IS_DELETED (xmop))
1308  {
1309  OID_SET_NULL (&lockset->objects[i].oid);
1310  }
1311  else
1312  {
1313  lockset->objects[i].chn = ws_chn (object);
1314  }
1315  }
1316  }
1317 
1318  return NO_ERROR;
1319 }
1320 
1321 /*
1322  * locator_get_rest_objects_classes:
1323  *
1324  * return : error code
1325  *
1326  * lockset(in/out):
1327  * class_mop(in/out):
1328  * class_obj(in/out):
1329  *
1330  * Note : Now get the rest of the objects and classes
1331  */
1332 static int
1333 locator_get_rest_objects_classes (LC_LOCKSET * lockset, MOP class_mop, MOBJ class_obj)
1334 {
1335  int error_code = NO_ERROR;
1336  int i, idx = 0;
1337  LC_COPYAREA *fetch_copyarea[MAX_FETCH_SIZE];
1338  LC_COPYAREA **fetch_ptr = fetch_copyarea;
1339 
1340  if (MAX (lockset->num_classes_of_reqobjs, lockset->num_reqobjs) > MAX_FETCH_SIZE)
1341  {
1342  fetch_ptr =
1343  (LC_COPYAREA **) malloc (sizeof (LC_COPYAREA *) * MAX (lockset->num_classes_of_reqobjs, lockset->num_reqobjs));
1344 
1345  if (fetch_ptr == NULL)
1346  {
1348  sizeof (LC_COPYAREA *) * MAX (lockset->num_classes_of_reqobjs, lockset->num_reqobjs));
1349 
1350  return ER_OUT_OF_VIRTUAL_MEMORY;
1351  }
1352  }
1353 
1354  while (lockset->num_classes_of_reqobjs > lockset->num_classes_of_reqobjs_processed
1355  || lockset->num_reqobjs > lockset->num_reqobjs_processed)
1356  {
1357  fetch_ptr[idx] = NULL;
1358  if (locator_fetch_lockset (lockset, &fetch_ptr[idx]) != NO_ERROR)
1359  {
1360  error_code = ER_FAILED;
1361  break;
1362  }
1363  if (fetch_ptr[idx] == NULL)
1364  {
1365  /* FIXME: This loop should have the same lifespan as the loop in slocator_fetch_lockset on server. Because
1366  * that loop stops when copy_area is NULL (fetch_ptr[idx] here), this loop should stop too or the client will
1367  * be stuck in this loop waiting for an answer that will never come. This is a temporary fix. NOTE: No error
1368  * is set on server, we will not set one here. */
1369  break;
1370  }
1371 
1372  idx++;
1373  }
1374 
1375  for (i = 0; i < idx; i++)
1376  {
1377  if (fetch_ptr[i] != NULL)
1378  {
1379  int ret = locator_cache (fetch_ptr[i], class_mop, class_obj, NULL,
1380  NULL);
1381  if (ret != NO_ERROR && error_code != NO_ERROR)
1382  {
1383  error_code = ret;
1384  }
1385 
1386  locator_free_copy_area (fetch_ptr[i]);
1387  }
1388  }
1389 
1390  if (fetch_ptr != fetch_copyarea)
1391  {
1392  free_and_init (fetch_ptr);
1393  }
1394 
1395  return error_code;
1396 }
1397 
1398 /*
1399  * locator_lock_nested () - Lock and fetch all nested objects/references of given
1400  * object
1401  *
1402  * return: NO_ERROR if all OK, ER status otherwise
1403  *
1404  * mop(in): Mop of the desired/graph_root object to lock
1405  * lock(in): Lock to acquire on the object and the nested objects
1406  * prune_level(in): Get nested references upto this level. If the value
1407  * is <= 0 means upto an infinite level (i.e., no pruning).
1408  * quit_on_errors(in): Quit when an error is found such as cannot lock all
1409  * nested objects.
1410  * fun(in): Function to call after a successful execution.
1411  * args(in): Arguments to the above function
1412  *
1413  * Note: The object associated with the given MOP and its direct and
1414  * indirect references upto a prune level are locked with the
1415  * given lock. The object locator in the server is always called
1416  * to find out and lock the nested references.
1417  * The object locator is not invoked and the references are not
1418  * found and locked if the desired object is cached with the
1419  * desired lock or with a more powerful lock and a function is
1420  * not given.
1421  * The function does not quit when an object in the nested
1422  * reference cannot be locked. The function tries to lock all the
1423  * objects at once, however if this fails and the function is
1424  * allowed to continue when errors are detected, the objects are
1425  * locked individually.
1426  */
1427 static int
1428 locator_lock_nested (MOP mop, LOCK lock, int prune_level, int quit_on_errors, int (*fun) (LC_LOCKSET * req, void *args),
1429  void *args)
1430 {
1431  OID *oid; /* OID of object to lock */
1432  MOBJ object; /* The desired object */
1433  LOCK current_lock; /* Current lock cached for desired object */
1434  int chn; /* Cache coherency number of object */
1435  MOP class_mop; /* Class mop of object to lock */
1436  OID *class_oid; /* Class identifier of object to lock */
1437  MOBJ class_obj; /* The class of the desired object */
1438  int class_chn; /* Cache coherency number of class of object to lock */
1439  MOP xmop; /* Temporarily mop area */
1440  LC_COPYAREA *fetch_area; /* Area where objects are received */
1441  LC_LOCKSET *lockset = NULL; /* Area for referenced objects */
1442  int level; /* The current listing level */
1443  int error_code = NO_ERROR;
1444  int i;
1445  LOCK conv_lock;
1446 
1447  if (WS_ISVID (mop))
1448  {
1449  /*
1450  * Don't know how to fetch virtual object. This looks like a system error
1451  * of the caller
1452  */
1453 #if defined(CUBRID_DEBUG)
1454  er_log_debug (ARG_FILE_LINE, "locator_lock_nested: ** SYSTEM ERROR don't know how to fetch virtual objects. ");
1456 #endif /* CUBRID_DEBUG */
1457  /* if this gets occurs in a production system, we want to guard against a crash & have the same test results as
1458  * the debug system. */
1459  return ER_GENERIC_ERROR;
1460  }
1461 
1462  oid = ws_oid (mop);
1463 
1464  if (ws_find (mop, &object) == WS_FIND_MOP_DELETED)
1465  {
1466  /* The object has been deleted */
1468  return ER_HEAP_UNKNOWN_OBJECT;
1469  }
1470 
1471  /*
1472  * Don't need to go to the server if the following holds:
1473  * 1: The object is cached
1474  * 2: We have the correct lock
1475  * 3: The object was fetched as part of a composition with the given level
1476  */
1477 
1478  current_lock = ws_get_lock (mop);
1479  assert (lock >= NULL_LOCK && current_lock >= NULL_LOCK);
1480  conv_lock = lock_Conv[lock][current_lock];
1481  assert (conv_lock != NA_LOCK);
1482 
1483  if (object != NULL && current_lock != NULL_LOCK && conv_lock == current_lock && WS_MOP_GET_COMPOSITION_FETCH (mop))
1484  {
1485  /* TODO: Is snapshot version relevant here? */
1486  level = (int) WS_MOP_GET_PRUNE_LEVEL (mop);
1487  if (level <= 0 || level >= prune_level)
1488  {
1489  /*
1490  * Don't need to go to the server
1491  */
1492  return NO_ERROR;
1493  }
1494  }
1495 
1496  chn = ws_chn (object);
1497  if (chn > NULL_CHN && sm_is_reuse_oid_class (mop))
1498  {
1499  /* Since an already cached object of a reuse_oid table may be deleted after it is cached to my workspace and
1500  * then another object may occupy its slot, unfortunately the cached CHN has no meaning. When the new object
1501  * occasionally has the same CHN with that of the cached object and we don't fetch the object from server again,
1502  * we will incorrectly reuse the cached deleted object. We need to refetch the cached object if it is an
1503  * instance of reuse_oid table. Server will fetch the object since client passes NULL_CHN. */
1504  chn = NULL_CHN;
1505  }
1506 
1507  /*
1508  * Get the class information for the desired object, just in case we need
1509  * to bring it from the server
1510  */
1511 
1512  class_mop = ws_class_mop (mop);
1513  if (class_mop == NULL)
1514  {
1515  /* Don't know the class. Server must figure it out */
1516  class_oid = NULL;
1517  class_obj = NULL;
1518  class_chn = NULL_CHN;
1519  }
1520  else
1521  {
1522  class_oid = ws_oid (class_mop);
1523  if (ws_find (class_mop, &class_obj) == WS_FIND_MOP_DELETED)
1524  {
1526  oid->slotid);
1528  }
1529  class_chn = ws_chn (class_obj);
1530  }
1531 
1532  /*
1533  * We need to ensure that the server knows about this object. So if the
1534  * object has a temporary OID or has never been flushed to the server,
1535  * (and is dirty) then do it now.
1536  */
1537  if (OID_ISTEMP (oid) || (WS_ISDIRTY (mop) && chn <= NULL_CHN))
1538  {
1539  error_code = locator_flush_instance (mop);
1540  if (error_code != NO_ERROR)
1541  {
1542  return error_code;
1543  }
1544  }
1545 
1546  /*
1547  * Lock the desired object and its references up to the prune level.
1548  * And bring the first batch of classes and objects
1549  */
1550 
1551  if (locator_fetch_all_reference_lockset (oid, chn, class_oid, class_chn, lock, quit_on_errors, prune_level, &lockset,
1552  &fetch_area) == NO_ERROR)
1553  {
1554  error_code = NO_ERROR;
1555  }
1556  else
1557  {
1558  error_code = ER_FAILED;
1559  }
1560 
1561  if (error_code == NO_ERROR && lockset != NULL && fetch_area != NULL)
1562  {
1563  error_code = locator_cache (fetch_area, class_mop, class_obj, NULL, NULL);
1564  locator_free_copy_area (fetch_area);
1565 
1566  if (error_code == NO_ERROR
1567  && (fun != NULL || lockset->num_classes_of_reqobjs > lockset->num_classes_of_reqobjs_processed
1568  || lockset->num_reqobjs > lockset->num_reqobjs_processed))
1569  {
1571 
1572  error_code = locator_get_rest_objects_classes (lockset, class_mop, class_obj);
1573  }
1574  }
1575 
1576  if (error_code == NO_ERROR && lockset != NULL)
1577  {
1578  /*
1579  * Cache the lock for the desired object and its references and their
1580  * class.
1581  */
1582 
1583  for (i = 0; i < lockset->num_classes_of_reqobjs; i++)
1584  {
1585  if (!OID_ISNULL (&lockset->classes[i].oid)
1586  && (xmop = ws_mop (&lockset->classes[i].oid, sm_Root_class_mop)) != NULL)
1587  {
1588  locator_cache_lock_set (xmop, NULL, lockset);
1589  }
1590  }
1591 
1592  for (i = 0; i < lockset->num_reqobjs; i++)
1593  {
1594  if (!OID_ISNULL (&lockset->objects[i].oid) && (xmop = ws_mop (&lockset->objects[i].oid, NULL)) != NULL)
1595  {
1596  locator_cache_lock_set (xmop, NULL, lockset);
1597  /*
1598  * Indicate that the object was fetched as a composite object
1599  */
1601  }
1602  } /* for (i = 0; ...) */
1603 
1604  if (WS_MOP_GET_COMPOSITION_FETCH (mop))
1605  {
1606  WS_MOP_SET_PRUNE_LEVEL (mop, prune_level);
1607  }
1608 
1609  /* Call the desired function.. for any additional tasks */
1610  if (fun != NULL)
1611  {
1612  error_code = (*fun) (lockset, args);
1613  }
1614  }
1615 
1616  if (lockset != NULL)
1617  {
1618  locator_free_lockset (lockset);
1619  }
1620 
1621  if (quit_on_errors == false)
1622  {
1623  /*
1624  * Make sure that there was not an error in the interested root nested
1625  * object
1626  */
1627  if (ws_find (mop, &object) == WS_FIND_MOP_DELETED)
1628  {
1629  /* The object has been deleted */
1630  oid = ws_oid (mop);
1632  error_code = ER_HEAP_UNKNOWN_OBJECT;
1633  }
1634  else
1635  {
1636  /* The only way to find out if there was an error, is by looking to acquired lock */
1637 
1638  current_lock = ws_get_lock (mop);
1639  assert (lock >= NULL_LOCK && current_lock >= NULL_LOCK);
1640  conv_lock = lock_Conv[lock][current_lock];
1641  assert (conv_lock != NA_LOCK);
1642 
1643  if (current_lock == NULL_LOCK || conv_lock != current_lock)
1644  {
1645  error_code = ER_FAILED;
1646  if (er_errid () == 0)
1647  {
1648  oid = ws_oid (mop);
1650  oid->slotid);
1651  error_code = ER_LC_LOCK_CACHE_ERROR;
1652  }
1653  }
1654  }
1655  }
1656 
1657  return error_code;
1658 }
1659 
1660 /*
1661  * locator_lock_class_of_instance () - Lock the class of an instance
1662  *
1663  * return: NO_ERROR if all OK, ER status otherwise
1664  *
1665  * inst_mop(in): Memory Object Pointer of instance
1666  * class_mop(in): Memory Object Pointer of class (set as a side effect)
1667  * lock(in): Lock to acquire
1668  *
1669  * Note: The class associated with the given instance MOP is locked
1670  * with the desired lock. The object locator on the server is not
1671  * invoked if the class is actually cached with the desired lock
1672  * or with a more powerful lock. In any other case, the object
1673  * locator on the server is invoked to acquire the desired lock
1674  * and possibly to bring the desired class along with some other
1675  * objects that may be prefetched.
1676  *
1677  * The main difference between this function and the locator_lock is
1678  * that the class_mop may not be know in the client.
1679  */
1680 static int
1681 locator_lock_class_of_instance (MOP inst_mop, MOP * class_mop, LOCK lock)
1682 {
1683  OID *inst_oid; /* Instance identifier */
1684  OID *class_oid; /* Class identifier of class to lock */
1685  int class_chn; /* Cache coherency number of class to lock */
1686  MOBJ class_obj = NULL; /* The class of the desired object */
1687  LOCK current_lock; /* Current lock cached for the class */
1688  LC_COPYAREA *fetch_area; /* Area where objects are received */
1689  int error_code = NO_ERROR;
1690  OID tmp_oid;
1691 
1692  inst_oid = ws_oid (inst_mop);
1693 
1694  /* Find the class mop */
1695 
1696  *class_mop = ws_class_mop (inst_mop);
1697  if (*class_mop != NULL && ws_find (*class_mop, &class_obj) == WS_FIND_MOP_DELETED)
1698  {
1700  inst_oid->slotid);
1702  }
1703 
1704  if (WS_ISVID (inst_mop) || (*class_mop != NULL && WS_ISVID (*class_mop)))
1705  {
1706 #if defined(CUBRID_DEBUG)
1707  /*
1708  * Don't know how to fetch virtual object. This looks like a system error
1709  * of the caller
1710  */
1712  "locator_lock_class_of_instance: ** SYSTEM ERROR don't know how to fetch virtual objects. ");
1714 #endif /* CUBRID_DEBUG */
1715  /* if this gets occurs in a production system, we want to guard against a crash & have the same test results as
1716  * the debug system. */
1717  return ER_GENERIC_ERROR;
1718  }
1719 
1720 #if defined (SA_MODE) && !defined (CUBRID_DEBUG)
1721  if (*class_mop != NULL && class_obj != NULL)
1722  {
1723  assert (lock >= NULL_LOCK && ws_get_lock (*class_mop) >= NULL_LOCK);
1724  lock = lock_Conv[lock][ws_get_lock (*class_mop)];
1725  assert (lock != NA_LOCK);
1726 
1727  ws_set_lock (*class_mop, lock);
1728  return NO_ERROR;
1729  }
1730 #endif /* SA_MODE && !CUBRID_DEBUG */
1731 
1732  /*
1733  * Invoke the transaction object locator on the server either:
1734  * a) We do not know the class (i.e., class_mop)
1735  * b) the class is not cached
1736  * c) the current lock acquired on the class is less powerful than the
1737  * requested lock.
1738  */
1739 
1740  if (*class_mop == NULL)
1741  {
1742  class_oid = NULL;
1743  class_chn = NULL_CHN;
1744  }
1745  else
1746  {
1747  class_oid = ws_oid (*class_mop);
1748  class_chn = ws_chn (class_obj);
1749  }
1750 
1751  if (class_obj != NULL && class_oid != NULL)
1752  {
1753  current_lock = ws_get_lock (*class_mop);
1754  if (current_lock != NULL_LOCK)
1755  {
1756  assert (lock >= NULL_LOCK && current_lock >= NULL_LOCK);
1757  lock = lock_Conv[lock][current_lock];
1758  assert (lock != NA_LOCK);
1759 
1760  if (lock == current_lock || OID_ISTEMP (class_oid))
1761  {
1762  return NO_ERROR;
1763  }
1764  }
1765  }
1766 
1767  /* We must invoke the transaction object locator on the server */
1768 
1769  if (class_oid == NULL)
1770  {
1771  class_oid = &tmp_oid;
1772  OID_SET_NULL (class_oid);
1773  }
1774 
1775  /* The only object that we request prefetching is the instance */
1776 
1777  if (locator_get_class (class_oid, class_chn, ws_oid (inst_mop), lock, false, &fetch_area) != NO_ERROR)
1778  {
1779  return ER_FAILED;
1780  }
1781  /* We were able to acquired the lock. Was the cached class valid ? */
1782 
1783  if (fetch_area != NULL)
1784  {
1785  /* Cache the objects that were brought from the server */
1786  error_code = locator_cache (fetch_area, NULL, NULL, NULL, NULL);
1787  locator_free_copy_area (fetch_area);
1788  if (error_code != NO_ERROR)
1789  {
1790  return error_code;
1791  }
1792  }
1793 
1794  /*
1795  * Cache the lock for the class.
1796  * We need to do this since we don't know if the class was received in
1797  * the fetch area
1798  */
1799  if (*class_mop == NULL)
1800  {
1801  *class_mop = ws_mop (class_oid, sm_Root_class_mop);
1802  }
1803 
1804  if (*class_mop != NULL)
1805  {
1806  ws_set_lock (*class_mop, lock);
1807  ws_set_class (inst_mop, *class_mop);
1808  }
1809 
1810  /* There was a failure. Was the transaction aborted ? */
1812  {
1813  (void) tran_abort_only_client (false);
1814  }
1815 
1816  return error_code;
1817 }
1818 
1819 /*
1820  * locator_lock_and_doesexist () - Lock, find if object exist, and prefetch it
1821  *
1822  * return: Either of (LC_EXIST, LC_DOESNOT_EXIST, LC_ERROR)
1823  *
1824  * mop(in): Mop of the object to lock
1825  * lock(in): Lock to acquire
1826  * isclass(in): LC_OBJTYPE of mop to find
1827  *
1828  * Note: The object associated with the given MOP is locked with the
1829  * desired lock. The object locator on the server is not invoked
1830  * if the object is actually cached with the desired lock or with
1831  * a more powerful lock. In any other case, the object locator on
1832  * server is invoked to acquire the lock, check the existence of
1833  * the object and possibly to bring the object along with other
1834  * objects which are stored on the same page of the desired
1835  * object. This is done for prefetching reasons.
1836  *
1837  * The only difference between this function and the locator_lock is
1838  * that error messages are not set if the object does not exist.
1839  */
1840 static int
1842 {
1843  LOCATOR_CACHE_LOCK cache_lock; /* Cache the lock */
1844  OID *oid; /* OID of object to lock */
1845  int chn; /* Cache coherency number of object */
1846  MOBJ object; /* The desired object */
1847  MOP class_mop; /* Class mop of object to lock */
1848  OID *class_oid; /* Class identifier of object to lock */
1849  int class_chn; /* Cache coherency number of class of object to lock */
1850  MOBJ class_obj; /* The class of the desired object */
1851  LC_COPYAREA *fetch_area; /* Area where objects are received */
1852  int doesexist;
1853  bool is_prefetch;
1854 
1855  oid = ws_oid (mop);
1856 
1857  if (WS_ISVID (mop))
1858  {
1859  MOP temp;
1860 
1861  /* get its real instance. */
1862  temp = db_real_instance (mop);
1863  if (temp != NULL && !WS_ISVID (temp))
1864  {
1865  mop = temp;
1866  }
1867  else
1868  {
1869  /* We could not find real instance. */
1870  ASSERT_ERROR ();
1871  return LC_ERROR;
1872  }
1873  }
1874 
1875  if (ws_find (mop, &object) == WS_FIND_MOP_DELETED)
1876  {
1877  /* The object has been deleted */
1878  return LC_DOESNOT_EXIST;
1879  }
1880 
1881 #if defined (SA_MODE) && !defined (CUBRID_DEBUG)
1882  if (object != NULL)
1883  {
1884  /* The object is cached */
1885  assert (lock >= NULL_LOCK && ws_get_lock (mop) >= NULL_LOCK);
1886  lock = lock_Conv[lock][ws_get_lock (mop)];
1887  assert (lock != NA_LOCK);
1888 
1889  ws_set_lock (mop, lock);
1890  return LC_EXIST;
1891  }
1892 #endif /* SA_MODE && !CUBRID_DEBUG */
1893 
1894  /*
1895  * Invoke the transaction object locator on the server either:
1896  * a) if the object is not cached
1897  * b) the current lock acquired on the object is less powerful
1898  * than the requested lock.
1899  */
1900 
1901  class_mop = ws_class_mop (mop);
1902 
1904  {
1905  return LC_EXIST;
1906  }
1907 
1908  /* We must invoke the transaction object locator on the server */
1909 
1910  cache_lock.oid = oid;
1911  cache_lock.lock = lock;
1912  cache_lock.isolation = TM_TRAN_ISOLATION ();
1914 
1915  /* Find the cache coherency numbers for fetching purposes */
1916  if (object == NULL && WS_IS_DELETED (mop))
1917  {
1918  /* Isn't this a duplicate check of ws_find == WS_FIND_MOP_DELETED? */
1919  return LC_DOESNOT_EXIST;
1920  }
1921 
1922  chn = ws_chn (object);
1923  if (chn > NULL_CHN && isclass != LC_CLASS && sm_is_reuse_oid_class (mop))
1924  {
1925  /* Since an already cached object of a reuse_oid table may be deleted after it is cached to my workspace and
1926  * then another object may occupy its slot, unfortunately the cached CHN has no meaning. When the new object
1927  * occasionally has the same CHN with that of the cached object and we don't fetch the object from server again,
1928  * * we will incorrectly reuse the cached deleted object. We need to refetch the cached object if it is an
1929  * instance of reuse_oid table. Server will fetch the object since client passes NULL_CHN. */
1930  chn = NULL_CHN;
1931  }
1932 
1933  /*
1934  * Get the class information for the desired object, just in case we need
1935  * to bring it from the server
1936  */
1937 
1938  if (class_mop == NULL)
1939  {
1940  class_oid = NULL;
1941  class_obj = NULL;
1942  class_chn = NULL_CHN;
1943  cache_lock.class_oid = class_oid;
1944  if (lock == NULL_LOCK)
1945  {
1946  cache_lock.class_lock = NULL_LOCK;
1947  cache_lock.implicit_lock = NULL_LOCK;
1948  }
1949  else
1950  {
1951  if (lock <= S_LOCK)
1952  {
1953  cache_lock.class_lock = IS_LOCK;
1954  }
1955  else
1956  {
1957  cache_lock.class_lock = IX_LOCK;
1958  }
1959  cache_lock.implicit_lock = NULL_LOCK;
1960  }
1961  }
1962  else
1963  {
1964  class_oid = ws_oid (class_mop);
1965  if (ws_find (class_mop, &class_obj) == WS_FIND_MOP_DELETED)
1966  {
1967  return LC_DOESNOT_EXIST;
1968  }
1969 
1970  class_chn = ws_chn (class_obj);
1971  cache_lock.class_oid = class_oid;
1972  if (lock == NULL_LOCK)
1973  {
1974  cache_lock.class_lock = ws_get_lock (class_mop);
1975  }
1976  else
1977  {
1978  if (lock <= S_LOCK)
1979  {
1980  cache_lock.class_lock = IS_LOCK;
1981  }
1982  else
1983  {
1984  cache_lock.class_lock = IX_LOCK;
1985  }
1986 
1987  assert (cache_lock.class_lock >= NULL_LOCK && ws_get_lock (class_mop) >= NULL_LOCK);
1988  cache_lock.class_lock = lock_Conv[cache_lock.class_lock][ws_get_lock (class_mop)];
1989  assert (cache_lock.class_lock != NA_LOCK);
1990 
1991  }
1992  /* Lock for prefetched instances of the same class */
1993  cache_lock.implicit_lock = locator_to_prefetched_lock (cache_lock.class_lock);
1994  }
1995 
1996  /* Now find the existance of the object in the database */
1997  if (cache_lock.implicit_lock != NULL_LOCK)
1998  {
1999  is_prefetch = true;
2000  }
2001  else
2002  {
2003  is_prefetch = false;
2004  }
2005  doesexist =
2006  locator_does_exist (oid, chn, lock, class_oid, class_chn, true, is_prefetch, &fetch_area,
2008  if (doesexist != LC_ERROR)
2009  {
2010  /* We were able to acquired the lock. Was the cached object valid ? */
2011 
2012  if (fetch_area != NULL)
2013  {
2014  /* Cache the objects that were brought from the server */
2015  if (locator_cache (fetch_area, class_mop, class_obj, locator_cache_lock, &cache_lock) != NO_ERROR)
2016  {
2017  doesexist = LC_ERROR;
2018  }
2019  locator_free_copy_area (fetch_area);
2020  }
2021 
2022  if (doesexist == LC_EXIST)
2023  {
2024  /*
2025  * Cache the lock for the object and its class.
2026  * We need to do this since we don't know if the object was received in
2027  * the fetch area
2028  */
2029 
2030  locator_cache_lock (mop, NULL, &cache_lock);
2031 
2032  if (class_mop != NULL)
2033  {
2034  locator_cache_lock (class_mop, NULL, &cache_lock);
2035  }
2036  }
2037  }
2038 
2039  if (doesexist == LC_ERROR && er_errid () == ER_LK_UNILATERALLY_ABORTED)
2040  {
2041  /* There was a failure. Was the transaction aborted ? */
2042  (void) tran_abort_only_client (false);
2043  }
2044 
2045  return doesexist;
2046 }
2047 
2048 /*
2049  * locator_fetch_mode_to_lock () - Find the equivalent lock for the given
2050  * db_fetch_mode
2051  *
2052  * return: lock
2053  *
2054  * purpose(in): Fetch purpose: Valid ones are:
2055  * DB_FETCH_READ
2056  * DB_FETCH_WRITE
2057  * DB_FETCH_DIRTY
2058  * DB_FETCH_CLREAD_INSTWRITE
2059  * DB_FETCH_CLREAD_INSTREAD
2060  * DB_FETCH_QUERY_READ
2061  * DB_FETCH_QUERY_WRITE
2062  * type(in): type of object that will need the above purpose
2063  * fetch_version_type(in): fetch version type
2064  *
2065  * Note:Find the equivalent lock for the given fetch purpose.
2066  */
2067 LOCK
2069 {
2070  LOCK lock;
2071 
2072 #if defined(CUBRID_DEBUG)
2073  if (type == LC_INSTANCE
2074  && (purpose == DB_FETCH_CLREAD_INSTREAD || purpose == DB_FETCH_CLREAD_INSTWRITE || purpose == DB_FETCH_QUERY_READ
2075  || purpose == DB_FETCH_QUERY_WRITE))
2076  {
2078  "locator_fetch_mode_to_lock: *** SYSTEM ERROR Fetching instance with incorrect "
2079  "fetch purpose mode = %d ... assume READ_FETCMODE...***\n", purpose);
2080  purpose = DB_FETCH_READ;
2081  }
2082 #endif /* CUBRID_DEBUG */
2083 
2084  switch (purpose)
2085  {
2086  default:
2087  assert (DB_FETCH_READ <= purpose && purpose <= DB_FETCH_EXCLUSIVE_SCAN);
2088  /* for release build, assume DB_FETCH_READ */
2089  /* fall through */
2090 
2091  case DB_FETCH_READ:
2092  if (type == LC_CLASS)
2093  {
2094  lock = SCH_S_LOCK;
2095  }
2096  else if (type == LC_INSTANCE)
2097  {
2098  if (fetch_version_type == LC_FETCH_DIRTY_VERSION)
2099  {
2100  lock = S_LOCK;
2101  }
2102  else
2103  {
2104  lock = NULL_LOCK;
2105  }
2106  }
2107  else
2108  {
2109  /* Since we don't know whether the object is class or instance, is the responsibility of the server to
2110  * transform this lock, when he finds instance. That's because an instance can't have intention lock. Then,
2111  * the client must cache the transformed lock. */
2112  lock = IS_LOCK;
2113  }
2114  break;
2115 
2116  case DB_FETCH_WRITE:
2117  if (type == LC_CLASS)
2118  {
2119  lock = SCH_M_LOCK;
2120  }
2121  else
2122  {
2123  lock = X_LOCK;
2124  }
2125  break;
2126 
2128  lock = IX_LOCK;
2129  break;
2130 
2132  lock = IS_LOCK;
2133  break;
2134 
2135  case DB_FETCH_QUERY_READ:
2136  lock = S_LOCK;
2137  break;
2138 
2139  case DB_FETCH_QUERY_WRITE:
2140  lock = SIX_LOCK;
2141  break;
2142 
2143  case DB_FETCH_DIRTY:
2144  lock = NULL_LOCK;
2145  break;
2146 
2147  case DB_FETCH_SCAN:
2148  assert (type == LC_CLASS);
2149  lock = S_LOCK;
2150  break;
2151 
2153  assert (type == LC_CLASS);
2154  lock = SIX_LOCK;
2155  break;
2156  }
2157 
2158  return lock;
2159 }
2160 
2161 /*
2162  * locator_get_cache_coherency_number () - Get cache coherency number
2163  *
2164  * return:
2165  *
2166  * mop(in): Memory Object Pointer of object to fetch
2167  *
2168  * Note: Find the cache coherency number of the given object.
2169  */
2170 int
2172 {
2173  MOP class_mop; /* Mop of class of the desired object */
2174  LOCK lock; /* Lock to acquire for the above purpose */
2175  MOBJ object; /* The desired object */
2176  LC_OBJTYPE isclass;
2177  LC_FETCH_VERSION_TYPE fetch_version_type = TM_TRAN_READ_FETCH_VERSION ();
2178 
2179  class_mop = ws_class_mop (mop);
2180  if (class_mop == NULL)
2181  {
2182  /* the server will decide the type of the lock */
2183  isclass = LC_OBJECT;
2184  }
2185  else if (locator_is_root (class_mop))
2186  {
2187  isclass = LC_CLASS;
2188  fetch_version_type = LC_FETCH_CURRENT_VERSION;
2189  }
2190  else
2191  {
2192  isclass = LC_INSTANCE;
2193  }
2194 
2195  lock = locator_fetch_mode_to_lock (DB_FETCH_READ, isclass, fetch_version_type);
2196  if (locator_lock (mop, isclass, lock, fetch_version_type) != NO_ERROR)
2197  {
2198  return NULL_CHN;
2199  }
2200  if (ws_find (mop, &object) == WS_FIND_MOP_DELETED)
2201  {
2202  return NULL_CHN;
2203  }
2204 
2205  return ws_chn (object);
2206 }
2207 
2208 /*
2209  * locator_fetch_object () - Fetch an object (instance or class)
2210  *
2211  * return:
2212  *
2213  * mop(in): Memory Object Pointer of object to fetch
2214  * purpose(in): Fetch purpose: Valid ones are:
2215  * DB_FETCH_READ
2216  * DB_FETCH_WRITE
2217  * DB_FETCH_DIRTY
2218  * DB_FETCH_CLREAD_INSTWRITE
2219  * DB_FETCH_CLREAD_INSTREAD
2220  * DB_FETCH_QUERY_READ
2221  * DB_FETCH_QUERY_WRITE
2222  * fetch_version_tyoe(in): fetch version type
2223  *
2224  * Note: Fetch the object associated with the given mop for the given
2225  * purpose
2226  *
2227  * Currently, this function is very simple. More complexity will
2228  * be added to support long duration transaction with the notion
2229  * of membership transactions, hard, soft, and broken locks.
2230  *
2231  * It is better if caller uses locator_fetch-instance or
2232  * locator_fetch-class
2233  */
2234 MOBJ
2236 {
2237  MOP class_mop; /* Mop of class of the desired object */
2238  LOCK lock; /* Lock to acquire for the above purpose */
2239  MOBJ object; /* The desired object */
2240  LC_OBJTYPE isclass;
2241 
2242  class_mop = ws_class_mop (mop);
2243  if (class_mop == NULL)
2244  {
2245  isclass = LC_OBJECT;
2246  }
2247  else if (locator_is_root (class_mop))
2248  {
2249  isclass = LC_CLASS;
2250  }
2251  else
2252  {
2253  isclass = LC_INSTANCE;
2254  }
2255 
2256  lock = locator_fetch_mode_to_lock (purpose, isclass, fetch_version_type);
2257  if (locator_lock (mop, isclass, lock, fetch_version_type) != NO_ERROR)
2258  {
2259  return NULL;
2260  }
2261  if (ws_find (mop, &object) == WS_FIND_MOP_DELETED)
2262  {
2263  return NULL;
2264  }
2265 
2266  return object;
2267 }
2268 
2269 /*
2270  * locator_fetch_class () - Fetch a class
2271  *
2272  * return: MOBJ
2273  *
2274  * class_mop(in):Memory Object Pointer of class to fetch
2275  * purpose(in): Fetch purpose: Valid ones:
2276  * DB_FETCH_READ
2277  * DB_FETCH_WRITE
2278  * DB_FETCH_DIRTY
2279  * DB_FETCH_CLREAD_INSTWRITE
2280  * DB_FETCH_CLREAD_INSTREAD
2281  * DB_FETCH_QUERY_READ
2282  * DB_FETCH_QUERY_WRITE
2283  *
2284  * Note: Fetch the class associated with the given mop for the given
2285  * purpose
2286  *
2287  * Currently, this function is very simple. More complexity will
2288  * be added to support long duration transaction with the notion
2289  * of membership transactions, hard, soft, and broken locks.
2290  * (See report on "Long Transaction Support")
2291  */
2292 MOBJ
2294 {
2295  LOCK lock; /* Lock to acquire for the above purpose */
2296  MOBJ class_obj; /* The desired class */
2297 
2298  if (class_mop == NULL)
2299  {
2300  return NULL;
2301  }
2302 
2303 #if defined(CUBRID_DEBUG)
2304  if (ws_class_mop (class_mop) != NULL)
2305  {
2306  if (!locator_is_root (ws_class_mop (class_mop)))
2307  {
2308  OID *oid;
2309 
2310  oid = ws_oid (class_mop);
2312  "locator_fetch_class: ***SYSTEM ERROR Incorrect"
2313  " use of function.\n Object OID %d|%d%d associated "
2314  "with argument class_mop is not a class.\n.."
2315  " Calling... locator_fetch_instance instead...***\n", oid->volid, oid->pageid, oid->slotid);
2316  return locator_fetch_instance (class_mop, purpose, LC_FETCH_MVCC_VERSION);
2317  }
2318  }
2319 #endif /* CUBRID_DEBUG */
2320 
2322  if (locator_lock (class_mop, LC_CLASS, lock, LC_FETCH_CURRENT_VERSION) != NO_ERROR)
2323  {
2324  return NULL;
2325  }
2326  if (ws_find (class_mop, &class_obj) == WS_FIND_MOP_DELETED)
2327  {
2328  return NULL;
2329  }
2330 
2331  return class_obj;
2332 }
2333 
2334 /*
2335  * locator_fetch_class_of_instance () - Fetch the class of given instance
2336  *
2337  * return: MOBJ of class
2338  *
2339  * inst_mop(in): Memory Object Pointer of instance
2340  * class_mop(in): Memory Object Pointer of class (set as a side effect)
2341  * purpose(in): Fetch purpose for the class fetch:
2342  * Valid ones:
2343  * DB_FETCH_READ
2344  * DB_FETCH_WRITE
2345  * DB_FETCH_DIRTY
2346  * DB_FETCH_CLREAD_INSTWRITE
2347  * DB_FETCH_CLREAD_INSTREAD
2348  * DB_FETCH_QUERY_READ
2349  * DB_FETCH_QUERY_WRITE
2350  *
2351  * Note: Fetch the class of the given instance for the given purposes.
2352  */
2353 MOBJ
2354 locator_fetch_class_of_instance (MOP inst_mop, MOP * class_mop, DB_FETCH_MODE purpose)
2355 {
2356  LOCK lock; /* Lock to acquire for the above purpose */
2357  MOBJ class_obj; /* The desired class */
2358 
2360  if (locator_lock_class_of_instance (inst_mop, class_mop, lock) != NO_ERROR)
2361  {
2362  return NULL;
2363  }
2364  if (ws_find (*class_mop, &class_obj) == WS_FIND_MOP_DELETED)
2365  {
2366  return NULL;
2367  }
2368 
2369  return class_obj;
2370 }
2371 
2372 /*
2373  * locator_fetch_instance () - Fetch an instance
2374  *
2375  * return: MOBJ
2376  *
2377  * mop(in): Memory Object Pointer of class to fetch
2378  * purpose(in): Fetch purpose: Valid ones:
2379  * DB_FETCH_READ
2380  * DB_FETCH_WRITE
2381  * DB_FETCH_DIRTY
2382  * fetch_version_type(in): Fetch version type
2383  *
2384  * Note: Fetch the instance associated with the given mop for the given
2385  * purpose
2386  *
2387  * Note: Currently, this function is very simple. More complexity will
2388  * be added to support long duration transaction with the notion
2389  * of membership transactions, hard, soft, and broken locks.
2390  * (See report on "Long Transaction Support")
2391  */
2392 MOBJ
2394 {
2395  LOCK lock; /* Lock to acquire for the above purpose */
2396  MOBJ inst; /* The desired instance */
2397 
2398 #if defined(CUBRID_DEBUG)
2399  if (ws_class_mop (mop) != NULL)
2400  {
2401  if (locator_is_root (ws_class_mop (mop)))
2402  {
2403  OID *oid;
2404 
2405  oid = ws_oid (mop);
2407  "locator_fetch_instance: SYSTEM ERROR Incorrect"
2408  " use of function.\n Object OID %d|%d|%d associated"
2409  " with argument mop is not an instance.\n Calling... locator_fetch_class instead..\n",
2410  oid->volid, oid->pageid, oid->slotid);
2411  return locator_fetch_class (mop, purpose);
2412  }
2413  }
2414 #endif /* CUBRID_DEBUG */
2415 
2416  inst = NULL;
2417  lock = locator_fetch_mode_to_lock (purpose, LC_INSTANCE, fetch_version_type);
2418  if (locator_lock (mop, LC_INSTANCE, lock, fetch_version_type) != NO_ERROR)
2419  {
2420  return NULL;
2421  }
2422  if (ws_find (mop, &inst) == WS_FIND_MOP_DELETED)
2423  {
2424  return NULL;
2425  }
2426 
2427  return inst;
2428 }
2429 
2430 /*
2431  * locator_fetch_set () - Fetch a set of objects (both instances and classes)
2432  *
2433  * return: MOBJ of the first MOP or NULL
2434  *
2435  * num_mops(in): Number of mops to to fetch
2436  * mop_set(in): A vector of mops to fetch
2437  * inst_purpose(in): Fetch purpose for requested objects that are instances:
2438  * Valid ones:
2439  * DB_FETCH_READ
2440  * DB_FETCH_WRITE
2441  * DB_FETCH_DIRTY
2442  * class_purpose(in): Fetch purpose for requested objects that are classes:
2443  * Valid ones:
2444  * DB_FETCH_READ
2445  * DB_FETCH_WRITE
2446  * DB_FETCH_DIRTY
2447  * DB_FETCH_CLREAD_INSTWRITE
2448  * DB_FETCH_CLREAD_INSTREAD
2449  * DB_FETCH_QUERY_READ
2450  * DB_FETCH_QUERY_WRITE
2451  * DB_FETCH_QUERY_WRITE
2452  * quit_on_errors(in): Wheater to continue fetching in case an error, such as
2453  * object does not exist, is found.
2454  *
2455  * Note:Fetch the objects associated with the given mops for the given
2456  * purpose. The function does not quit when an error is found if
2457  * the value of quit_on_errors is false. In this case the object
2458  * with the error is not locked/fetched. The function tries to
2459  * lock all the objects at once, however if this fails and the
2460  * function is allowed to continue when errors are detected, the
2461  * objects are locked individually.
2462  */
2463 MOBJ
2464 locator_fetch_set (int num_mops, MOP * mop_set, DB_FETCH_MODE inst_purpose, DB_FETCH_MODE class_purpose,
2465  int quit_on_errors)
2466 {
2467  LOCK reqobj_class_lock; /* Lock to acquire for requested objects that are classes */
2468  LOCK reqobj_inst_lock; /* Lock to acquire for requested objects that are instances */
2469  MOBJ object; /* The desired object of the first mop */
2470 
2471  if (num_mops <= 0)
2472  {
2473  return NULL;
2474  }
2475 
2476  if (num_mops == 1)
2477  {
2478  MOP first = mop_set[0];
2479  /* convert vmop into a base mop here for the singleton case. locator_lock_set will handle the conversion of
2480  * multiple vmops. */
2481  if (WS_ISVID (first))
2482  {
2483  /* get its real instance */
2484  MOP temp = db_real_instance (first);
2485  if (temp && !WS_ISVID (temp))
2486  {
2487  first = temp;
2488  }
2489  }
2490  /* Execute a simple fetch */
2491  if (ws_class_mop (first) == sm_Root_class_mop)
2492  {
2493  return locator_fetch_class (first, class_purpose);
2494  }
2495  else
2496  {
2497  return locator_fetch_instance (first, inst_purpose, TM_TRAN_READ_FETCH_VERSION ());
2498  }
2499  }
2500 
2501  reqobj_inst_lock = locator_fetch_mode_to_lock (inst_purpose, LC_INSTANCE, TM_TRAN_READ_FETCH_VERSION ());
2502  reqobj_class_lock = locator_fetch_mode_to_lock (class_purpose, LC_CLASS, LC_FETCH_CURRENT_VERSION);
2503 
2504  object = NULL;
2505  if (locator_lock_set (num_mops, mop_set, reqobj_inst_lock, reqobj_class_lock, quit_on_errors) != NO_ERROR)
2506  {
2507  return NULL;
2508  }
2509  if (ws_find (*mop_set, &object) == WS_FIND_MOP_DELETED)
2510  {
2511  return NULL;
2512  }
2513 
2514  return object;
2515 }
2516 
2517 /*
2518  * locator_fetch_nested () - Nested fetch. the given object and its references
2519  *
2520  * return: MOBJ of MOP or NULL in case of error
2521  *
2522  * mop(in): Memory Object Pointer of desired object (the graph root of
2523  * references)
2524  * purpose(in): Fetch purpose for requested objects and its references
2525  * Valid ones:
2526  * DB_FETCH_READ
2527  * DB_FETCH_WRITE
2528  * DB_FETCH_DIRTY
2529  * prune_level(in): Get nested references upto this level. If the value is <= 0
2530  * means upto an infinite level (i.e., no pruning).
2531  * quit_on_errors(in): Wheater to continue fetching in case an error, such as
2532  * object does not exist, is found.
2533  *
2534  * Note: Fetch the object associated with the given mop and its direct
2535  * and indirect references upto the given prune level with the
2536  * given purpose. A negative prune level means infinite. The
2537  * function does not quit when an error is found in a reference
2538  * if the value of quit_on_errors is false. In this case the
2539  * referenced object with the error is not locked/fetched. The
2540  * function tries to lock all the objects at once, however if
2541  * this fails and the function is allowed to continue when errors
2542  * are detected, the objects are locked individually.
2543  *
2544  * If the needed references are known by the caller he should
2545  * call locator_fetch_set instead since the overhead of finding the
2546  * nestead references can be eliminated.
2547  */
2548 MOBJ
2549 locator_fetch_nested (MOP mop, DB_FETCH_MODE purpose, int prune_level, int quit_on_errors)
2550 {
2551  LOCK lock; /* Lock to acquire for the above purpose */
2552  MOBJ inst; /* The desired instance */
2553 
2554 #if defined(CUBRID_DEBUG)
2555  if (ws_class_mop (mop) != NULL)
2556  {
2557  if (locator_is_root (ws_class_mop (mop)))
2558  {
2559  OID *oid;
2560 
2561  oid = ws_oid (mop);
2563  "locator_fetch_nested: SYSTEM ERROR Incorrect use of function.\n "
2564  "Object OID %d|%d|%d associated with argument mop is "
2565  "not an instance.\n Calling locator_fetch_class instead..\n", oid->volid, oid->pageid,
2566  oid->slotid);
2567  return locator_fetch_class (mop, purpose);
2568  }
2569  }
2570 #endif /* CUBRID_DEBUG */
2571 
2572  inst = NULL;
2574  if (locator_lock_nested (mop, lock, prune_level, quit_on_errors, NULL, NULL) != NO_ERROR)
2575  {
2576  return NULL;
2577  }
2578  if (ws_find (mop, &inst) == WS_FIND_MOP_DELETED)
2579  {
2580  return NULL;
2581  }
2582 
2583  return inst;
2584 }
2585 
2586 /*
2587  * locator_keep_mops () - Append mop to list of mops
2588  *
2589  * return: LIST_MOPS * (Must be deallocated by caller)
2590  *
2591  * mop(in): Mop of an object
2592  * object(in): The object .. ignored
2593  * kmops(in): The keep most list of mops (set as a side effect)
2594  *
2595  * Note:Append the mop to the list of mops.
2596  */
2597 static void
2598 locator_keep_mops (MOP mop, MOBJ object, void *kmops)
2599 {
2600  LOCATOR_LIST_KEEP_MOPS *keep_mops;
2601  LOCK lock;
2602 
2603  keep_mops = (LOCATOR_LIST_KEEP_MOPS *) kmops;
2604 
2605  assert (keep_mops->lock >= NULL_LOCK && ws_get_lock (mop) >= NULL_LOCK);
2606  lock = lock_Conv[keep_mops->lock][ws_get_lock (mop)];
2607  assert (lock != NA_LOCK);
2608 
2609  ws_set_lock (mop, lock);
2610  if (keep_mops->fun != NULL && object != NULL)
2611  {
2612  if (((*keep_mops->fun) (object)) == false)
2613  {
2614  return;
2615  }
2616  }
2617  (keep_mops->list->mops)[keep_mops->list->num++] = mop;
2618 }
2619 
2620 /*
2621  * locator_fun_get_all_mops () - Get all instance mops of the given class. return only
2622  * the ones that satisfy the client function
2623  *
2624  * return: LIST_MOPS * (Must be deallocated by caller)
2625  *
2626  * class_mop(in): Class mop of the instances
2627  * purpose(in): Fetch purpose: Valid ones:
2628  * DB_FETCH_DIRTY (Will not lock)
2629  * DB_FETCH_QUERY_READ
2630  * DB_FETCH_QUERY_WRITE
2631  * fun(in): Function to call on each object of class. If the function
2632  * returns false, the object is not returned to the caller.
2633  * force_fetch_version_type(in): Fetch version type
2634  *
2635  * Note: Find out all the instances (mops) of a given class. The
2636  * instances of the class are prefetched for future references.
2637  * The list of mops is returned to the caller.
2638  * The force_fetch_version_type parameter, allow to users to specify
2639  * desired fetch version type. The user must carefully set this
2640  * parameter. Thus, if force_fetch_version_type is dirty and
2641  * class is IX-locked, the instance is fetched without lock,
2642  * and the user must lock the instance later before using it.
2643  */
2644 static LIST_MOPS *
2645 locator_fun_get_all_mops (MOP class_mop, DB_FETCH_MODE purpose, int (*fun) (MOBJ class_obj),
2646  LC_FETCH_VERSION_TYPE * force_fetch_version_type)
2647 {
2648  LOCATOR_LIST_KEEP_MOPS keep_mops;
2649  LC_COPYAREA *fetch_area; /* Area where objects are received */
2650  HFID *hfid;
2651  OID *class_oid;
2652  OID last_oid;
2653  MOBJ class_obj;
2654  LOCK lock;
2655  size_t size;
2656  int nobjects;
2657  int estimate_nobjects;
2658  int nfetched;
2659  int error_code = NO_ERROR;
2660  LC_FETCH_VERSION_TYPE fetch_version_type;
2661 
2662  /* Get the class */
2663  class_oid = ws_oid (class_mop);
2664  class_obj = locator_fetch_class (class_mop, purpose);
2665  if (class_obj == NULL)
2666  {
2667  /* Unable to fetch class to find out its instances */
2668  return NULL;
2669  }
2670 
2671  /* Find the desired lock on the class */
2673  if (lock == NULL_LOCK)
2674  {
2675  lock = ws_get_lock (class_mop);
2676  }
2677  else
2678  {
2679  assert (lock >= NULL_LOCK && ws_get_lock (class_mop) >= NULL_LOCK);
2680  lock = lock_Conv[lock][ws_get_lock (class_mop)];
2681  assert (lock != NA_LOCK);
2682  }
2683 
2684  /*
2685  * Find the implicit lock to be acquired by the instances
2686  */
2687 
2688  keep_mops.fun = fun;
2689  keep_mops.lock = locator_to_prefetched_lock (lock);
2690  keep_mops.list = NULL;
2691 
2692  /* Find the heap where the instances are stored */
2693  hfid = sm_ch_heap (class_obj);
2694  if (hfid->vfid.fileid == NULL_FILEID)
2695  {
2696  return NULL;
2697  }
2698 
2699  /* Flush all the instances */
2700 
2702  {
2703  return NULL;
2704  }
2705 
2706  nobjects = 0;
2707  nfetched = -1;
2708  estimate_nobjects = -1;
2709  OID_SET_NULL (&last_oid);
2710 
2711  /*
2712  * Since shared or exclusive class lock is requested, the purpose is to
2713  * update class or instances (we do not allow such locks at select).
2714  * In read committed, using MVCC version may lead to issues. Thus, we may
2715  * select deleted objects (still visible for the current transaction)
2716  * and later (same command) we may try to update already deleted object.
2717  * In read committed, when class share or exclusive lock is requested,
2718  * we can fetch dirty version of the instances. These instance versions are
2719  * updatable instance versions for the current command. Also, these instance
2720  * versions are visible versions for the next command of the transaction.
2721  * In RR and SERIALIZABLE, we have to use MVCC version. Otherwise, we may
2722  * update an instance that's not visible for current transaction, instead of
2723  * returning SERIALIZABLE conflict (snapshot is acquired once / transaction).
2724  */
2725 
2726  if (force_fetch_version_type == NULL)
2727  {
2728  if ((lock == S_LOCK || lock >= SIX_LOCK) && (TM_TRAN_ISOLATION () == TRAN_READ_COMMITTED))
2729  {
2730  fetch_version_type = LC_FETCH_DIRTY_VERSION;
2731  }
2732  else
2733  {
2734  fetch_version_type = LC_FETCH_MVCC_VERSION;
2735  }
2736  }
2737  else
2738  {
2739  fetch_version_type = *force_fetch_version_type;
2740  }
2741 
2742  /* Now start fetching all the instances and build a list of the mops */
2743 
2744  while (nobjects != nfetched)
2745  {
2746  /*
2747  * Note that the number of object and the number of fetched objects are
2748  * updated by the locator_fetch_all function on the server
2749  */
2750  error_code =
2751  locator_fetch_all (hfid, &lock, fetch_version_type, class_oid, &nobjects, &nfetched, &last_oid, &fetch_area);
2752  if (error_code != NO_ERROR)
2753  {
2754  /* There was a failure. Was the transaction aborted ? */
2756  {
2757  (void) tran_abort_only_client (false);
2758  }
2759  if (keep_mops.list != NULL)
2760  {
2761  locator_free_list_mops (keep_mops.list);
2762  keep_mops.list = NULL;
2763  }
2764  break;
2765  }
2766  /*
2767  * Cache the objects, that were brought from the server
2768  */
2769  if (fetch_area == NULL)
2770  {
2771  /* No more objects */
2772  break;
2773  }
2774 
2775  /*
2776  * If the list of mops is NULL, this is the first time.. allocate the
2777  * list and continue retrieving the objects
2778  */
2779  if (estimate_nobjects < nobjects)
2780  {
2781  estimate_nobjects = nobjects;
2782  size = sizeof (*keep_mops.list) + (nobjects * sizeof (MOP *));
2783  if (keep_mops.list == NULL)
2784  {
2785  keep_mops.list = (LIST_MOPS *) malloc (size);
2786  if (keep_mops.list == NULL)
2787  {
2788  locator_free_copy_area (fetch_area);
2790  break;
2791  }
2792  keep_mops.list->num = 0;
2793  }
2794  else
2795  {
2796  keep_mops.list = (LIST_MOPS *) realloc (keep_mops.list, size);
2797  if (keep_mops.list == NULL)
2798  {
2799  locator_free_copy_area (fetch_area);
2801  break;
2802  }
2803  }
2804  }
2805  error_code = locator_cache (fetch_area, class_mop, class_obj, locator_keep_mops, &keep_mops);
2806  locator_free_copy_area (fetch_area);
2807  } /* while */
2808 
2809  if (keep_mops.list != NULL && keep_mops.lock == NULL_LOCK && locator_is_root (class_mop)
2810  && (lock == IS_LOCK || lock == IX_LOCK))
2811  {
2812  if (locator_lock_set (keep_mops.list->num, keep_mops.list->mops, lock, lock, true) != NO_ERROR)
2813  {
2814  locator_free_list_mops (keep_mops.list);
2815  keep_mops.list = NULL;
2816  }
2817  }
2818 
2819  return keep_mops.list;
2820 }
2821 
2822 /*
2823  * locator_get_all_mops () - Get all instance mops
2824  *
2825  * return: LIST_MOPS * (Must be deallocated by caller)
2826  *
2827  * class_mop(in): Class mop of the instances
2828  * purpose(in): Fetch purpose: Valid ones:
2829  * DB_FETCH_DIRTY (Will not lock)
2830  * DB_FETCH_QUERY_READ
2831  * DB_FETCH_QUERY_WRITE
2832  * force_fetch_version_type(in): fetch version type
2833  *
2834  * Note: Find out all the instances (mops) of a given class. The
2835  * instances of the class are prefetched for future references.
2836  * The list of mops is returned to the caller.
2837  */
2838 LIST_MOPS *
2839 locator_get_all_mops (MOP class_mop, DB_FETCH_MODE purpose, LC_FETCH_VERSION_TYPE * force_fetch_version_type)
2840 {
2841  return locator_fun_get_all_mops (class_mop, purpose, NULL, force_fetch_version_type);
2842 }
2843 
2844 /*
2845  * locator_get_all_class_mops () - Return all class mops that satisfy the client
2846  * function
2847  *
2848  * return: LIST_MOPS * (Must be deallocated by caller)
2849  *
2850  * purpose(in): Fetch purpose: Valid ones:
2851  * DB_FETCH_DIRTY (Will not lock)
2852  * DB_FETCH_QUERY_READ
2853  * DB_FETCH_QUERY_WRITE
2854  * fun(in): Function to call on each object of class. If the function
2855  * returns false, the object is not returned to the caller.
2856  *
2857  * Note: Find out all the classes that satisfy the given client
2858  * function.
2859  */
2860 LIST_MOPS *
2861 locator_get_all_class_mops (DB_FETCH_MODE purpose, int (*fun) (MOBJ class_obj))
2862 {
2863  return locator_fun_get_all_mops (sm_Root_class_mop, purpose, fun, NULL);
2864 }
2865 
2866 /*
2867  * locator_save_nested_mops () - Construct list of nested references
2868  *
2869  * return: NO_ERROR if all OK, ER status otherwise
2870  *
2871  * lockset(in): Request of the desired object and its nested references
2872  * save_mops(in):
2873  *
2874  * Note:Construct a list of all nested references including the given
2875  * object.
2876  */
2877 static int
2878 locator_save_nested_mops (LC_LOCKSET * lockset, void *save_mops)
2879 {
2880  int i;
2881  LOCATOR_LIST_NESTED_MOPS *nested = (LOCATOR_LIST_NESTED_MOPS *) save_mops;
2882  size_t size = sizeof (*nested->list) + (lockset->num_reqobjs * sizeof (MOP *));
2883 
2884  if (lockset->num_reqobjs <= 0)
2885  {
2886  nested->list = NULL;
2887  return NO_ERROR;
2888  }
2889 
2890  nested->list = (LIST_MOPS *) malloc (size);
2891  if (nested->list == NULL)
2892  {
2894  return ER_OUT_OF_VIRTUAL_MEMORY;
2895  }
2896  nested->list->num = 0;
2897  for (i = 0; i < lockset->num_reqobjs; i++)
2898  {
2899  if (!OID_ISNULL (&lockset->objects[i].oid))
2900  {
2901  (nested->list->mops)[nested->list->num++] = ws_mop (&lockset->objects[i].oid, NULL);
2902  }
2903  }
2904 
2905  return NO_ERROR;
2906 }
2907 
2908 #if defined (ENABLE_UNUSED_FUNCTION)
2909 /*
2910  * locator_get_all_nested_mops () - Get all nested mops of the given mop object
2911  *
2912  * return: LIST_MOPS * (Must be deallocated by caller)
2913  *
2914  * mop(in): Memory Object Pointer of desired object (the graph root of
2915  * references)
2916  * prune_level(in): Get nested references upto this level. If the value is <= 0
2917  * means upto an infinite level (i.e., no pruning).
2918  * inst_purpose(in):
2919  *
2920  * Note: Traverse the given object finding all direct and indirect
2921  * references upto the given prune level. A negative prune level
2922  * means infnite (i.e., find all nested references).
2923  *
2924  * This function can be used to store the references of an object
2925  * into another object, this will allow future used of the
2926  * locator_fetch_set function wich is more efficient than the
2927  * locator_fetch_nested function since the finding of the references is
2928  * skipped.
2929  */
2930 LIST_MOPS *
2931 locator_get_all_nested_mops (MOP mop, int prune_level, DB_FETCH_MODE inst_purpose)
2932 {
2933  LOCATOR_LIST_NESTED_MOPS nested;
2934  LOCK lock; /* Lock to acquire for the above purpose */
2935 
2936 #if defined(CUBRID_DEBUG)
2937  if (ws_class_mop (mop) != NULL)
2938  {
2939  if (locator_is_root (ws_class_mop (mop)))
2940  {
2941  OID *oid;
2942 
2943  oid = ws_oid (mop);
2945  "locator_get_all_nested_mops: SYSTEM ERROR Incorrect use of function.\n Object OID %d|%d|%d"
2946  " associated with argument mop is not an instance.\n"
2947  " Calling locator_fetch_class instead..\n", oid->volid, oid->pageid, oid->slotid);
2948  return NULL;
2949  }
2950  }
2951 #endif /* CUBRID_DEBUG */
2952 
2953  lock = locator_fetch_mode_to_lock (inst_purpose, LC_INSTANCE);
2954  nested.list = NULL;
2955  if (locator_lock_nested (mop, lock, prune_level, true, locator_save_nested_mops, &nested) != NO_ERROR)
2956  {
2957  if (nested.list != NULL)
2958  {
2959  locator_free_list_mops (nested.list);
2960  nested.list = NULL;
2961  }
2962  }
2963 
2964  return nested.list;
2965 }
2966 #endif
2967 
2968 /*
2969  * locator_free_list_mops () - Free the list of all instance mops
2970  *
2971  * return: nothing
2972  *
2973  * mops(in): Structure of mops(See function locator_get_all_mops)
2974  *
2975  * Note: Free the LIST_MOPS.
2976  */
2977 void
2979 {
2980  int i;
2981 
2982  /*
2983  * before freeing the array, NULL out all the MOP pointers so we don't
2984  * become a GC root for all of those MOPs.
2985  */
2986  if (mops != NULL)
2987  {
2988  for (i = 0; i < mops->num; i++)
2989  {
2990  mops->mops[i] = NULL;
2991  }
2992  free_and_init (mops);
2993  }
2994 }
2995 
2996 static LC_FIND_CLASSNAME
2997 locator_find_class_by_oid (MOP * class_mop, const char *classname, OID * class_oid, LOCK lock)
2998 {
2999  LC_FIND_CLASSNAME found;
3000  int error_code;
3001 
3002  assert (classname != NULL);
3003 
3004  /* Need to check the classname to oid in the server */
3005  *class_mop = NULL;
3006  found = locator_find_class_oid (classname, class_oid, lock);
3007  switch (found)
3008  {
3009  case LC_CLASSNAME_EXIST:
3010  *class_mop = ws_mop (class_oid, sm_Root_class_mop);
3011  if (*class_mop == NULL || WS_IS_DELETED (*class_mop))
3012  {
3013  *class_mop = NULL;
3015  {
3016  found = LC_CLASSNAME_ERROR;
3017  }
3018  else
3019  {
3021  }
3022 
3023  return found;
3024  }
3025 
3026  /* no need to get last version for class */
3027  error_code = locator_lock (*class_mop, LC_CLASS, lock, LC_FETCH_CURRENT_VERSION);
3028  if (error_code != NO_ERROR)
3029  {
3030  /*
3031  * Fetch the class object so that it gets properly interned in
3032  * the workspace class table. If we don't do that we can go
3033  * through here a zillion times until somebody actually *looks*
3034  * at the class object (not just its oid).
3035  */
3036  *class_mop = NULL;
3037  found = LC_CLASSNAME_ERROR;
3038  }
3039  break;
3040 
3041  case LC_CLASSNAME_DELETED:
3043  break;
3044 
3045  case LC_CLASSNAME_ERROR:
3047  {
3048  (void) tran_abort_only_client (false);
3049  }
3050  break;
3051 
3052  default:
3053  break;
3054  }
3055 
3056  return found;
3057 }
3058 
3059 /*
3060  * locator_find_class_by_name () - Find mop of a class by the classname
3061  *
3062  * return: LC_FIND_CLASSNAME
3063  * (either of LC_CLASSNAME_EXIST,
3064  * LC_CLASSNAME_DELETED
3065  * LC_CLASSNAME_ERROR)
3066  * class_mop is set as a side effect
3067  *
3068  * classname(in): Name of class to search
3069  * lock(in): Lock to apply on the class
3070  * class_mop(in): A pointer to mop of the class (Set as a side effect)
3071  *
3072  * Note: Find the mop of the class with the given classname. The class
3073  * is locked with the lock specified by the caller. The class
3074  * object may be brought to the client for future references.
3075  * A class_mop value of NULL means either that the class does not
3076  * exist or that an error was found. Thus, the return value
3077  * should be check for an error.
3078  */
3079 static LC_FIND_CLASSNAME
3080 locator_find_class_by_name (const char *classname, LOCK lock, MOP * class_mop)
3081 {
3082  OID class_oid; /* Class object identifier */
3083  LOCK current_lock;
3085 
3086  if (classname == NULL)
3087  {
3088  *class_mop = NULL;
3089  return LC_CLASSNAME_ERROR;
3090  }
3091 
3092  OID_SET_NULL (&class_oid);
3093 
3094  /*
3095  * Check if the classname to OID entry is cached. Trust the cache only if
3096  * there is a lock on the class
3097  */
3098  *class_mop = ws_find_class (classname);
3099  if (*class_mop == NULL)
3100  {
3101  found = locator_find_class_by_oid (class_mop, classname, &class_oid, lock);
3102  return found;
3103  }
3104 
3105  current_lock = ws_get_lock (*class_mop);
3106  if (current_lock == NULL_LOCK)
3107  {
3108  found = locator_find_class_by_oid (class_mop, classname, &class_oid, lock);
3109  return found;
3110  }
3111 
3112  if (WS_IS_DELETED (*class_mop))
3113  {
3115  *class_mop = NULL;
3116  found = LC_CLASSNAME_DELETED;
3117  }
3118  else
3119  {
3120  /* no need to get last version for class */
3121  if (locator_lock (*class_mop, LC_CLASS, lock, LC_FETCH_CURRENT_VERSION) != NO_ERROR)
3122  {
3123  *class_mop = NULL;
3124  found = LC_CLASSNAME_ERROR;
3125  }
3126  }
3127 
3128  return found;
3129 }
3130 
3131 /*
3132  * locator_find_class () - Find mop of a class
3133  *
3134  * return: MOP
3135  *
3136  * classname(in): Name of class to search
3137  *
3138  * Note: Find the mop of the class with the given classname. The class
3139  * object may be brought to the client for future references.
3140  */
3141 MOP
3142 locator_find_class (const char *classname)
3143 {
3144  MOP class_mop;
3145  LOCK lock = SCH_S_LOCK; /* This is done to avoid some deadlocks caused by our parsing */
3146 
3147  if (locator_find_class_by_name (classname, lock, &class_mop) != LC_CLASSNAME_EXIST)
3148  {
3149  class_mop = NULL;
3150  }
3151 
3152  return class_mop;
3153 }
3154 
3155 /*
3156  * locator_find_class_with_purpose () - Find mop of a class
3157  *
3158  * return: MOP
3159  *
3160  * classname(in): Name of class to search
3161  * for_update: true, if search the class for update purpose
3162  *
3163  * Note: Find the mop of the class with the given classname. The class
3164  * object may be brought to the client for future references.
3165  */
3166 MOP
3167 locator_find_class_with_purpose (const char *classname, bool for_update)
3168 {
3169  MOP class_mop;
3170  LOCK lock = SCH_S_LOCK; /* This is done to avoid some deadlocks caused by our parsing */
3171  if (for_update == false)
3172  {
3173  lock = SCH_S_LOCK;
3174  }
3175  else
3176  {
3177  lock = SCH_M_LOCK;
3178  }
3179 
3180  if (locator_find_class_by_name (classname, lock, &class_mop) != LC_CLASSNAME_EXIST)
3181  {
3182  class_mop = NULL;
3183  }
3184 
3185  return class_mop;
3186 }
3187 
3188 #if defined (ENABLE_UNUSED_FUNCTION)
3189 /*
3190  * locator_find_query_class () - Find mop of a class to be query
3191  *
3192  * return: LC_FIND_CLASSNAME
3193  * (either of LC_CLASSNAME_EXIST,
3194  * LC_CLASSNAME_DELETED
3195  * LC_CLASSNAME_ERROR)
3196  * class_mop is set as a side effect
3197  *
3198  * classname(in): Name of class to search
3199  * purpose(in): Fetch purpose: Valid ones:
3200  * DB_FETCH_QUERY_READ
3201  * DB_FETCH_QUERY_WRITE
3202  * class_mop(in/out): A pointer to mop of the class
3203  *
3204  * Note: Find the mop of the class with the given classname. The class
3205  * is locked with either share or exclusive lock depending on the
3206  * purpose indicated by the caller. The class object may be
3207  * brought to the client for future references.
3208  * A class_mop value of NULL means either that the class does not
3209  * exist or that an error was found. Thus, the return value
3210  * should be check for an error.
3211  */
3213 locator_find_query_class (const char *classname, DB_FETCH_MODE purpose, MOP * class_mop)
3214 {
3215  LOCK lock;
3216 
3217  lock = locator_fetch_mode_to_lock (purpose, LC_CLASS);
3218 
3219  return locator_find_class_by_name (classname, lock, class_mop);
3220 }
3221 #endif
3222 
3223 /*
3224  * locator_does_exist_object () - Does object exist ?
3225  *
3226  * return: Either of (LC_EXIST, LC_DOESNOT_EXIST, LC_ERROR)
3227  *
3228  * mop(in): Memory Object Pointer of object to fetch
3229  * purpose(in): Fetch purpose: Valid ones are:
3230  * DB_FETCH_READ
3231  * DB_FETCH_WRITE
3232  * DB_FETCH_DIRTY
3233  * DB_FETCH_CLREAD_INSTWRITE
3234  * DB_FETCH_CLREAD_INSTREAD
3235  * DB_FETCH_QUERY_READ
3236  * DB_FETCH_QUERY_WRITE
3237  *
3238  * Note: Find if the object exist and lock the object for the given
3239  * purpose. If the object does not exist, errors are not set.
3240  */
3241 int
3243 {
3244  MOP class_mop; /* Class Mop of the desired object */
3245  LOCK lock; /* Lock to acquire for the above purpose */
3246  LC_OBJTYPE isclass;
3247 
3248  class_mop = ws_class_mop (mop);
3249  if (class_mop == NULL)
3250  {
3251  isclass = LC_OBJECT;
3252  }
3253  else if (locator_is_root (class_mop))
3254  {
3255  isclass = LC_CLASS;
3256  }
3257  else
3258  {
3259  isclass = LC_INSTANCE;
3260  }
3261 
3262  lock = locator_fetch_mode_to_lock (purpose, isclass, TM_TRAN_READ_FETCH_VERSION ());
3263 
3264  return locator_lock_and_doesexist (mop, lock, isclass);
3265 }
3266 
3267 /*
3268  * locator_decache_lock () - Decache lock of given object
3269  *
3270  * return: WS_MAP_CONTINUE
3271  *
3272  * mop(in): mop
3273  * ignore(in): ignored
3274  *
3275  * Note: Decache all locks of instances of given class.
3276  */
3277 static int
3278 locator_decache_lock (MOP mop, void *ignore)
3279 {
3280  ws_set_lock (mop, NULL_LOCK);
3281 
3282  return WS_MAP_CONTINUE;
3283 }
3284 
3285 /*
3286  * locator_decache_all_lock_instances () - Decache all lock of instances of class
3287  *
3288  * return: NO_ERROR if all OK, ER status otherwise
3289  *
3290  * class_mop(in): Class mop
3291  */
3292 int
3294 {
3296  {
3297  return NO_ERROR;
3298  }
3299  else
3300  {
3301  return ER_FAILED;
3302  }
3303 }
3304 
3305 /*
3306  * locator_cache_object_class () -
3307  *
3308  * return: NO_ERROR if all OK, ER status otherwise
3309  *
3310  * mop(in/out):
3311  * obj(in/out):
3312  * object_p(in/out):
3313  * recdes_p(in/out):
3314  * call_fun(in/out):
3315  *
3316  * Note:
3317  */
3318 static int
3319 locator_cache_object_class (MOP mop, LC_COPYAREA_ONEOBJ * obj, MOBJ * object_p, RECDES * recdes_p, bool * call_fun)
3320 {
3321  int error_code = NO_ERROR;
3322 
3323  switch (obj->operation)
3324  {
3325  case LC_FETCH:
3326  *object_p = tf_disk_to_class (&obj->oid, recdes_p);
3327  if (*object_p == NULL)
3328  {
3329  error_code = ER_FAILED;
3331  {
3332  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
3333  }
3334 
3335  break;
3336  }
3337 
3338  ws_cache (*object_p, mop, sm_Root_class_mop);
3339  break;
3340 
3341  case LC_FETCH_DECACHE_LOCK:
3342  /*
3343  * We have brought the object. Recache it when its cache
3344  * coherency number has changed.
3345  *
3346  * We need to release the lock on its instances as well.
3347  * The instances could have been altered under certain
3348  * isolation levels or the class has been updated.
3349  */
3350  error_code = locator_decache_all_lock_instances (mop);
3351  if (error_code != NO_ERROR)
3352  { /* an error should have been set */
3353  break;
3354  }
3355 
3356  if (*object_p == NULL || WS_CHN (*object_p) != or_chn (recdes_p))
3357  {
3358  *object_p = tf_disk_to_class (&obj->oid, recdes_p);
3359  if (*object_p == NULL)
3360  {
3361  /* an error should have been set */
3363  {
3364  return ER_OUT_OF_VIRTUAL_MEMORY;
3365  }
3366  error_code = ER_FAILED;
3367  }
3368  else
3369  {
3370  ws_cache (*object_p, mop, sm_Root_class_mop);
3371  }
3372  }
3373  ws_set_lock (mop, NULL_LOCK);
3374  *call_fun = false;
3375  break;
3376  default:
3377 #if defined(CUBRID_DEBUG)
3379  "locator_cache: ** SYSTEM ERROR unknown fetch state operation for object = %d|%d|%d",
3380  obj->oid.volid, obj->oid.pageid, obj->oid.slotid);
3382 #endif /* CUBRID_DEBUG */
3383  error_code = ER_FAILED;
3384  }
3385 
3386  return error_code;
3387 }
3388 
3389 /*
3390  * locator_cache_object_instance () -
3391  *
3392  * return: NO_ERROR if all OK, ER status otherwise
3393  *
3394  * mop(in/out):
3395  * class_mop(in/out):
3396  * hint_class_mop_p(in/out):
3397  * hint_class_p(in/out):
3398  * obj(in/out):
3399  * object_p(in/out):
3400  * recdes_p(in/out):
3401  * call_fun(in/out):
3402  *
3403  * Note:
3404  */
3405 static int
3406 locator_cache_object_instance (MOP mop, MOP class_mop, MOP * hint_class_mop_p, MOBJ * hint_class_p,
3407  LC_COPYAREA_ONEOBJ * obj, MOBJ * object_p, RECDES * recdes_p, bool * call_fun)
3408 {
3409  int error_code = NO_ERROR;
3410  int ignore;
3411 
3412  switch (obj->operation)
3413  {
3414  case LC_FETCH:
3415  if (class_mop != *hint_class_mop_p)
3416  {
3417  *hint_class_p = locator_fetch_class (class_mop, DB_FETCH_CLREAD_INSTREAD);
3418  if (*hint_class_p == NULL)
3419  {
3420  error_code = ER_FAILED;
3422  {
3423  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
3424  }
3425  break;
3426  }
3427  *hint_class_mop_p = class_mop;
3428  }
3429 
3430  /* Transform the object and cache it */
3431  *object_p = tf_disk_to_mem (*hint_class_p, recdes_p, &ignore);
3432  if (*object_p == NULL)
3433  {
3434  /* an error should have been set */
3435  error_code = ER_FAILED;
3436  break;
3437  }
3438 
3439  ws_cache (*object_p, mop, class_mop);
3440  break;
3441 
3442  case LC_FETCH_DECACHE_LOCK:
3443  /*
3444  * We have brought the object. Recache it when its cache
3445  * coherency number has changed.
3446  */
3447  if (*object_p == NULL || WS_CHN (*object_p) != or_chn (recdes_p) || sm_is_reuse_oid_class (class_mop))
3448  {
3449  *object_p = tf_disk_to_mem (*hint_class_p, recdes_p, &ignore);
3450  if (*object_p == NULL)
3451  {
3452  /* an error should have been set */
3453  error_code = ER_FAILED;
3455  {
3456  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
3457  }
3458  break;
3459  }
3460 
3461  ws_cache (*object_p, mop, class_mop);
3462  }
3463 
3464  ws_set_lock (mop, NULL_LOCK);
3465  *call_fun = false;
3466  break;
3467  default:
3468 #if defined(CUBRID_DEBUG)
3470  "locator_cache: ** SYSTEM ERROR unknown fetch state operation for object = %d|%d|%d",
3471  obj->oid.volid, obj->oid.pageid, obj->oid.slotid);
3473 #endif /* CUBRID_DEBUG */
3474  error_code = ER_FAILED;
3475  }
3476 
3477  return error_code;
3478 }
3479 
3480 /*
3481  * locator_cache_not_have_object () -
3482  *
3483  * return: NO_ERROR if all OK, ER status otherwise
3484  *
3485  * mop_p(in/out):
3486  * object_p(in/out):
3487  * call_fun(in/out):
3488  * obj(in/out):
3489  *
3490  * Note:
3491  */
3492 static int
3493 locator_cache_not_have_object (MOP * mop_p, MOBJ * object_p, bool * call_fun, LC_COPYAREA_ONEOBJ * obj)
3494 {
3495  MOP class_mop; /* The class mop of object described by obj */
3496  int error_code = NO_ERROR;
3497 
3498  /*
3499  * We do not have the object. This is a delete or a decache operation.
3500  * We cannot know if this is an instance or a class
3501  */
3502  *mop_p = ws_mop (&obj->oid, NULL);
3503  if (*mop_p == NULL)
3504  {
3505  error_code = ER_FAILED;
3507  {
3508  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
3509  }
3510  return error_code;
3511  }
3512 
3513  if (obj->operation == LC_FETCH_DECACHE_LOCK
3514  || (ws_find (*mop_p, object_p) != WS_FIND_MOP_DELETED && (*object_p == NULL || !WS_ISDIRTY (*mop_p))))
3515  {
3516  switch (obj->operation)
3517  {
3518  case LC_FETCH_DELETED:
3519  *object_p = NULL;
3520  WS_SET_FOUND_DELETED (*mop_p);
3521  break;
3522 
3523  case LC_FETCH_DECACHE_LOCK:
3524  /*
3525  * Next time we access this object we need to go to server.
3526  * Note that we do not remove the object.
3527  *
3528  * If this is a class, we need to release the lock on its
3529  * instances as well. The instances could have been altered
3530  * under certain isolation levels or the class has been
3531  * updated.
3532  */
3533  class_mop = ws_class_mop (*mop_p);
3534  if (class_mop != NULL && locator_is_root (class_mop) == true)
3535  {
3536  error_code = locator_decache_all_lock_instances (*mop_p);
3537  if (error_code != NO_ERROR)
3538  { /* an error should have been set */
3539  return error_code;
3540  }
3541  }
3542  ws_set_lock (*mop_p, NULL_LOCK);
3543  *call_fun = false;
3544  break;
3545 
3546  case LC_FETCH_VERIFY_CHN:
3547  /*
3548  * Make sure that the cached object is current
3549  * NOTE that the server sent the cached coherency number in the
3550  * length field of the object.
3551  */
3552  if (*object_p == NULL || (WS_CHN (*object_p) != (-obj->length)))
3553  {
3554  ws_decache (*mop_p);
3555  ws_set_lock (*mop_p, NULL_LOCK);
3556  *call_fun = false;
3557  }
3558  break;
3559  default:
3560 #if defined(CUBRID_DEBUG)
3562  "locator_cache: ** SYSTEM ERROR fetch operation without the content of the"
3563  " object = %d|%d|%d", obj->oid.volid, obj->oid.pageid, obj->oid.slotid);
3565 #endif /* CUBRID_DEBUG */
3566  error_code = ER_FAILED;
3567  }
3568  }
3569 
3570  return error_code;
3571 }
3572 
3573 /*
3574  * locator_cache_have_object () -
3575  *
3576  * return: NO_ERROR if all OK, ER status otherwise
3577  *
3578  * mop_p(in/out):
3579  * object_p(in/out):
3580  * recdes_p(in/out):
3581  * hint_class_mop_p(in/out):
3582  * hint_class_p(in/out):
3583  * call_fun(in/out):
3584  * obj(in/out):
3585  *
3586  * Note:
3587  */
3588 static int
3589 locator_cache_have_object (MOP * mop_p, MOBJ * object_p, RECDES * recdes_p, MOP * hint_class_mop_p, MOBJ * hint_class_p,
3590  bool * call_fun, LC_COPYAREA_ONEOBJ * obj)
3591 {
3592  MOP class_mop; /* The class mop of object described by obj */
3593  int error_code = NO_ERROR;
3594 
3595  if (OID_IS_ROOTOID (&obj->class_oid))
3596  {
3597  /* Object is a class */
3598  *mop_p = ws_mop (&obj->oid, sm_Root_class_mop);
3599  if (*mop_p == NULL)
3600  {
3601 #if defined(CUBRID_DEBUG)
3602  er_log_debug (ARG_FILE_LINE, "locator_cache: ** SYSTEM ERROR unable to create mop for object = %d|%d|%d",
3603  obj->oid.volid, obj->oid.pageid, obj->oid.slotid);
3605 #endif /* CUBRID_DEBUG */
3606  error_code = ER_FAILED;
3608  {
3609  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
3610  }
3611 
3612  return error_code;
3613  }
3614 
3615  /*
3616  * Don't need to transform the object, when the object is cached
3617  * and has a valid state (same chn)
3618  */
3619 
3620  if ((ws_find (*mop_p, object_p) != WS_FIND_MOP_DELETED
3621  && (*object_p == NULL || (!WS_ISDIRTY (*mop_p) && WS_CHN (*object_p) != or_chn (recdes_p))))
3622  || obj->operation == LC_FETCH_DECACHE_LOCK)
3623  {
3624  error_code = locator_cache_object_class (*mop_p, obj, object_p, recdes_p, call_fun);
3625  if (error_code != NO_ERROR)
3626  {
3627  return error_code;
3628  }
3629  }
3630  /*
3631  * Assume that this class is going to be needed to transform other
3632  * objects in the copy area, so remember the class
3633  */
3634  *hint_class_mop_p = *mop_p;
3635  *hint_class_p = *object_p;
3636  }
3637  else
3638  {
3639  /* Object is an instance */
3640  class_mop = ws_mop (&obj->class_oid, sm_Root_class_mop);
3641  if (class_mop == NULL)
3642  {
3643  error_code = ER_FAILED;
3645  {
3646  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
3647  }
3648  return error_code;
3649  }
3650  *mop_p = ws_mop (&obj->oid, class_mop);
3651  if (*mop_p == NULL)
3652  {
3653 #if defined(CUBRID_DEBUG)
3654  er_log_debug (ARG_FILE_LINE, "locator_cache: ** SYSTEM ERROR unable to create mop for object = %d|%d|%d",
3655  obj->oid.volid, obj->oid.pageid, obj->oid.slotid);
3657 #endif /* CUBRID_DEBUG */
3658  error_code = ER_FAILED;
3660  {
3661  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
3662  }
3663 
3664  return error_code;
3665  }
3666 
3667  /*
3668  * Don't need to transform the object, when the object is cached and
3669  * has a valid state (same chn and not an object of reuse_oid table)
3670  */
3671  if (obj->operation == LC_FETCH_DECACHE_LOCK
3672  || (ws_find (*mop_p, object_p) != WS_FIND_MOP_DELETED
3673  && (*object_p == NULL
3674  || (!WS_ISDIRTY (*mop_p)
3675  && (WS_CHN (*object_p) != or_chn (recdes_p) || sm_is_reuse_oid_class (class_mop))))))
3676  {
3677  error_code =
3678  locator_cache_object_instance (*mop_p, class_mop, hint_class_mop_p, hint_class_p, obj, object_p, recdes_p,
3679  call_fun);
3680  if (error_code != NO_ERROR)
3681  {
3682  return error_code;
3683  }
3684  }
3685  /* Update the object mvcc snapshot version, so it won't be re-fetched while current snapshot is still valid. */
3687  }
3688 
3689  return error_code;
3690 }
3691 
3692 /*
3693  * locator_cache () - Cache several objects
3694  *
3695  * return: NO_ERROR if all OK, ER status otherwise
3696  *
3697  * copy_area(in): Copy area where objects are placed
3698  * hint_class_mop(in): The class mop of probably the objects placed in copy_area
3699  * hint_class(in): The class object of the hinted class
3700  * fun(in): Function to call with mop, object, and args
3701  * args(in): Arguments to be passed to function
3702  *
3703  * Note: Cache the objects stored on the given area. If the
3704  * caching fails for any object, then return error code.
3705  */
3706 static int
3707 locator_cache (LC_COPYAREA * copy_area, MOP hint_class_mop, MOBJ hint_class,
3708  void (*fun) (MOP mop, MOBJ object, void *args), void *args)
3709 {
3710  LC_COPYAREA_MANYOBJS *mobjs; /* Describe multiple objects in area */
3711  LC_COPYAREA_ONEOBJ *obj; /* Describe an object in area */
3712  MOP mop; /* Mop of the object described by obj */
3713  MOBJ object; /* The object described by obj */
3714  RECDES recdes; /* record descriptor for transformations */
3715  int i;
3716  bool call_fun;
3717  int error_code = NO_ERROR;
3718 
3719  mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (copy_area);
3720  obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (mobjs);
3721  obj = LC_PRIOR_ONEOBJ_PTR_IN_COPYAREA (obj);
3722 
3723  if (hint_class_mop && hint_class == NULL)
3724  {
3725  hint_class_mop = NULL;
3726  }
3727 
3728  /* Cache one object at a time */
3729  for (i = 0; i < mobjs->num_objs; i++)
3730  {
3731  call_fun = true;
3732  obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (obj);
3733  LC_RECDES_TO_GET_ONEOBJ (copy_area, obj, &recdes);
3734  object = NULL;
3735  mop = NULL;
3736 
3737  if (recdes.length < 0)
3738  {
3739  error_code = locator_cache_not_have_object (&mop, &object, &call_fun, obj);
3740  if (error_code != NO_ERROR)
3741  {
3742  if (error_code == ER_OUT_OF_VIRTUAL_MEMORY)
3743  {
3744  return error_code;
3745  }
3746  continue;
3747  }
3748  }
3749  else
3750  {
3751  error_code = locator_cache_have_object (&mop, &object, &recdes, &hint_class_mop, &hint_class, &call_fun, obj);
3752  if (error_code != NO_ERROR)
3753  {
3754  if (error_code == ER_OUT_OF_VIRTUAL_MEMORY)
3755  {
3756  return error_code;
3757  }
3758  continue;
3759  }
3760  }
3761 
3762  /* Call the given function to do additional tasks */
3763  if (call_fun == true)
3764  {
3765  if (fun != NULL)
3766  {
3767  (*fun) (mop, object, args);
3768  }
3769  else
3770  {
3771  if (mop != NULL && ws_class_mop (mop) == sm_Root_class_mop && ws_get_lock (mop) == NULL_LOCK)
3772  {
3773  ws_set_lock (mop, SCH_S_LOCK);
3774  }
3775  }
3776  }
3777  }
3778 
3779  return error_code;
3780 }
3781 
3782 /*
3783  * locator_mflush_initialize () - Initialize the mflush area
3784  *
3785  * return: NO_ERROR if all OK, ER status otherwise
3786  *
3787  * mflush(in): Structure which describes objects to flush
3788  * class_mop(in): Mop of the class of last instance mflushed. This is a hint
3789  * to avoid a lot of class fetching during transformations
3790  * class(in): The class object of the hinted class mop
3791  * hfid(in): The heap of instances of the hinted class
3792  * decache(in): true if objects must be decached after they are flushed
3793  * isone_mflush(in): true if process stops after one set of objects (i.e., one area) has been flushed to server.
3794  *
3795  * Note: Initialize the mflush structure which describes the objects in disk format to flush.
3796  * A copy area of one page is defined to place the objects.
3797  */
3798 static int
3799 locator_mflush_initialize (LOCATOR_MFLUSH_CACHE * mflush, MOP class_mop, MOBJ class_obj, HFID * hfid, bool decache,
3800  bool isone_mflush)
3801 {
3802  int error_code;
3803 
3804  assert (mflush != NULL);
3805 
3806  /* Guess that only one page is needed */
3807  mflush->copy_area = NULL;
3808  error_code = locator_mflush_reallocate_copy_area (mflush, DB_PAGESIZE);
3809  if (error_code != NO_ERROR)
3810  {
3811  return error_code;
3812  }
3813 
3814  mflush->class_mop = class_mop;
3815  mflush->class_obj = class_obj;
3816  mflush->hfid = hfid;
3817  mflush->decache = decache;
3818  mflush->isone_mflush = isone_mflush;
3819 
3820  return error_code;
3821 }
3822 
3823 /*
3824  * locator_mflush_reset () - Reset the mflush area
3825  *
3826  * return: nothing
3827  *
3828  * mflush(in): Structure which describes objects to flush
3829  *
3830  * Note: Reset the mflush structure which describes objects in disk format to flush to server.
3831  * This function is used after a an flush area has been forced.
3832  */
3833 static void
3835 {
3836  assert (mflush != NULL);
3837 
3838  mflush->mop_toids = NULL;
3839  mflush->mop_uoids = NULL;
3840  mflush->mop_tail_toid = NULL;
3841  mflush->mop_tail_uoid = NULL;
3842  mflush->mobjs->num_objs = 0;
3843  mflush->obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (mflush->mobjs);
3844  LC_RECDES_IN_COPYAREA (mflush->copy_area, &mflush->recdes);
3845 }
3846 
3847 /*
3848  * locator_mflush_reallocate_copy_area () - Reallocate copy area and reset flush area
3849  *
3850  * return: NO_ERROR if all OK, ER status otherwise
3851  *
3852  * mflush(in): Structure which describes objects to flush
3853  * minsize(in): Minimal size of flushing copy area
3854  *
3855  * Note: Reset the mflush structure which describes objects in disk format to flush.
3856  */
3857 static int
3859 {
3860  assert (mflush != NULL);
3861 
3862  if (mflush->copy_area != NULL)
3863  {
3865  }
3866 
3867  mflush->copy_area = locator_allocate_copy_area_by_length (minsize);
3868  if (mflush->copy_area == NULL)
3869  {
3870  return ER_OUT_OF_VIRTUAL_MEMORY;
3871  }
3872 
3873  mflush->mop_toids = NULL;
3874  mflush->mop_tail_toid = NULL;
3875  mflush->mop_uoids = NULL;
3876  mflush->mop_tail_uoid = NULL;
3877  mflush->mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (mflush->copy_area);
3878  mflush->mobjs->multi_update_flags = 0;
3879  mflush->mobjs->num_objs = 0;
3880  mflush->obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (mflush->mobjs);
3881  LC_RECDES_IN_COPYAREA (mflush->copy_area, &mflush->recdes);
3882 
3883  return NO_ERROR;
3884 }
3885 
3886 /*
3887  * locator_mflush_end - End the mflush area
3888  *
3889  * return: nothing
3890  *
3891  * mflush(in): Structure which describes objects to flush
3892  *
3893  * Note: The mflush area is terminated. The copy_area is deallocated.
3894  */
3895 static void
3897 {
3898  LOCATOR_MFLUSH_TEMP_OID *mop_toid;
3899  LOCATOR_MFLUSH_TEMP_OID *next_mop_toid;
3900 
3901  assert (mflush != NULL);
3902 
3903  if (mflush->mop_toids != NULL)
3904  {
3905  mop_toid = mflush->mop_toids;
3906  while (mop_toid != NULL)
3907  {
3908  next_mop_toid = mop_toid->next;
3909 
3910  free_and_init (mop_toid);
3911  mop_toid = next_mop_toid;
3912  }
3913  mflush->mop_toids = NULL;
3914  }
3915 
3916  if (mflush->mop_uoids != NULL)
3917  {
3918  mop_toid = mflush->mop_uoids;
3919  while (mop_toid != NULL)
3920  {
3921  next_mop_toid = mop_toid->next;
3922 
3923  free_and_init (mop_toid);
3924  mop_toid = next_mop_toid;
3925  }
3926  mflush->mop_uoids = NULL;
3927  }
3928 
3929  if (mflush->copy_area != NULL)
3930  {
3932  }
3933 }
3934 
3935 #if defined(CUBRID_DEBUG)
3936 /*
3937  * locator_dump_mflush () - Dump the mflush structure
3938  *
3939  * return: nothing
3940  *
3941  * mflush(in): Structure which describe objects to flush
3942  *
3943  * Note: Dump the mflush area. This function is used for DEBUGGING PURPOSES.
3944  */
3945 static void
3946 locator_dump_mflush (FILE * out_fp, LOCATOR_MFLUSH_CACHE * mflush)
3947 {
3948  fprintf (out_fp, "\n***Dumping mflush area ***\n");
3949 
3950  fprintf (out_fp, "Num_objects = %d, Area = %p, Area Size = %d, Available_area_at = %p, Available area size = %d\n",
3951  mflush->mobjs->num_objs, (void *) (mflush->copy_area->mem), (int) mflush->copy_area->length,
3952  mflush->recdes.data, mflush->recdes.area_size);
3953 
3954  locator_dump_copy_area (out_fp, mflush->copy_area, false);
3955 
3956  if (mflush->recdes.area_size >
3957  ((mflush->copy_area->length - sizeof (LC_COPYAREA_MANYOBJS) -
3958  mflush->mobjs->num_objs * sizeof (LC_COPYAREA_ONEOBJ))))
3959  {
3960  fprintf (stdout, "Bad mflush structure");
3961  }
3962 }
3963 #endif /* CUBRID_DEBUG */
3964 
3965 /*
3966  * locator_mflush_set_dirty () - Set object dirty/used when mflush failed
3967  *
3968  * return: nothing
3969  *
3970  * mop(in): Mop of object to recover
3971  * ignore_object(in): The object that has been chached
3972  * ignore_argument(in):
3973  *
3974  * Note: Set the given object as dirty. This function is used when mflush failed
3975  */
3976 static void
3977 locator_mflush_set_dirty (MOP mop, MOBJ ignore_object, void *ignore_argument)
3978 {
3979  ws_dirty (mop);
3980 }
3981 
3982 /*
3983  * locator_repl_mflush_force () - Force the mflush area
3984  *
3985  * return:
3986  *
3987  * mflush(in): Structure which describes to objects to flush
3988  *
3989  * Note: The repl objects placed on the mflush area are forced to the server (page buffer pool).
3990  */
3991 static int
3993 {
3994  LC_COPYAREA *reply_copy_area = NULL;
3995  int error_code = NO_ERROR;
3996 
3997  assert (mflush != NULL);
3998 
3999  /* Force the objects stored in area */
4000  if (mflush->mobjs->num_objs > 0)
4001  {
4002  error_code = locator_repl_force (mflush->copy_area, &reply_copy_area);
4003 
4004  /* If the force failed and the system is down.. finish */
4005  if (error_code == ER_LK_UNILATERALLY_ABORTED
4006  || ((error_code != NO_ERROR && error_code != ER_LC_PARTIALLY_FAILED_TO_FLUSH)
4007  && !BOOT_IS_CLIENT_RESTARTED ()))
4008  {
4009  return error_code;
4010  }
4011 
4012  if (error_code == ER_LC_PARTIALLY_FAILED_TO_FLUSH)
4013  {
4014  locator_repl_mflush_check_error (reply_copy_area);
4015  }
4016  }
4017 
4018  if (reply_copy_area != NULL)
4019  {
4020  locator_free_copy_area (reply_copy_area);
4021  }
4022 
4023  /* Now reset the flushing area... and continue flushing */
4024  locator_mflush_reset (mflush);
4025 
4026  return error_code;
4027 }
4028 
4029 /*
4030  * locator_repl_mflush_check_error () - save error info for later use
4031  *
4032  * return: void
4033  *
4034  * reply_copyarea(in):
4035  */
4036 static void
4038 {
4039  LC_COPYAREA_MANYOBJS *mobjs;
4041  char *content_ptr;
4042  int i;
4043 
4044  mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (reply_copyarea);
4045 
4046  for (i = 0; i < mobjs->num_objs; i++)
4047  {
4048  obj = LC_FIND_ONEOBJ_PTR_IN_COPYAREA (mobjs, i);
4049  content_ptr = reply_copyarea->mem + obj->offset;
4050 
4051  ws_set_repl_error_into_error_link (obj, content_ptr);
4052  }
4053 
4054  return;
4055 }
4056 
4057 /*
4058  * locator_mflush_force () - Force the mflush area
4059  *
4060  * return: NO_ERROR if all OK, ER status otherwise
4061  *
4062  * mflush(in): Structure which describes to objects to flush
4063  *
4064  * Note: The disk objects placed on the mflush area are forced to the server (page buffer pool).
4065  */
4066 static int
4068 {
4069  LOCATOR_MFLUSH_TEMP_OID *mop_toid;
4070  LOCATOR_MFLUSH_TEMP_OID *next_mop_toid;
4071  LC_COPYAREA_ONEOBJ *obj; /* Describe one object in copy area */
4072  OID *oid;
4073  int error_code = NO_ERROR;
4074  int i;
4075  int content_size = 0;
4076 
4077  assert (mflush != NULL);
4078 
4079  /* Force the objects stored in area */
4080  if (mflush->mobjs->num_objs >= 0)
4081  {
4082  /*
4083  * If there are objects with temporarily OIDs, make sure that they still
4084  * have temporarily OIDs. For those that do not have temporarily OIDs any
4085  * longer, change the flushing area to reflect the change. A situation
4086  * like this can happen when an object being placed in the flushing area
4087  * reference a new object which is already been placed in the flushing
4088  * area.
4089  */
4090 
4091  mop_toid = mflush->mop_toids;
4092  while (mop_toid != NULL)
4093  {
4094  oid = ws_oid (mop_toid->mop);
4095  if (!OID_ISTEMP (oid))
4096  {
4097  /* The OID of the object has already been assigned */
4098  obj = LC_FIND_ONEOBJ_PTR_IN_COPYAREA (mflush->mobjs, mop_toid->obj);
4099  COPY_OID (&obj->oid, oid);
4100  /* TODO: see if you need to look for partitions here */
4101  obj->operation = LC_FLUSH_UPDATE;
4102  mop_toid->mop = NULL;
4103  }
4104  mop_toid = mop_toid->next;
4105  }
4106 
4107  /* Force the flushing area */
4108  content_size = CAST_BUFLEN (mflush->recdes.data - mflush->copy_area->mem);
4109  assert (content_size >= 0);
4110  error_code = locator_force (mflush->copy_area, ws_Error_ignore_count, ws_Error_ignore_list, content_size);
4111 
4112  assert (error_code != ER_LC_PARTIALLY_FAILED_TO_FLUSH);
4113 
4114  /* If the force failed and the system is down.. finish */
4115  if (error_code == ER_LK_UNILATERALLY_ABORTED || (error_code != NO_ERROR && !BOOT_IS_CLIENT_RESTARTED ()))
4116  {
4117  /* Free the memory ... and finish */
4118  mop_toid = mflush->mop_toids;
4119  while (mop_toid != NULL)
4120  {
4121  next_mop_toid = mop_toid->next;
4122  /*
4123  * Set mop to NULL before freeing the structure, so that it does not
4124  * become a GC root for this mop..
4125  */
4126  mop_toid->mop = NULL;
4127  free_and_init (mop_toid);
4128  mop_toid = next_mop_toid;
4129  }
4130  mflush->mop_toids = NULL;
4131 
4132  mop_toid = mflush->mop_uoids;
4133  while (mop_toid != NULL)
4134  {
4135  next_mop_toid = mop_toid->next;
4136  /*
4137  * Set mop to NULL before freeing the structure, so that it does not
4138  * become a GC root for this mop..
4139  */
4140  mop_toid->mop = NULL;
4141  free_and_init (mop_toid);
4142  mop_toid = next_mop_toid;
4143  }
4144  mflush->mop_uoids = NULL;
4145 
4146  return error_code;
4147  }
4148 
4149  /*
4150  * Notify the workspace module of OIDs for new objects. The MOPs must
4151  * refelect the new OID.. and not the temporarily OID
4152  */
4153 
4154  mop_toid = mflush->mop_toids;
4155  while (mop_toid != NULL)
4156  {
4157  if (mop_toid->mop != NULL)
4158  {
4159  obj = LC_FIND_ONEOBJ_PTR_IN_COPYAREA (mflush->mobjs, mop_toid->obj);
4160  if (error_code != NO_ERROR && OID_ISNULL (&obj->oid))
4161  {
4162  COPY_OID (&obj->oid, ws_oid (mop_toid->mop));
4163  }
4164  else if (!OID_ISNULL (&obj->oid) && !(OID_ISTEMP (&obj->oid)))
4165  {
4166  ws_update_oid_and_class (mop_toid->mop, &obj->oid, &obj->class_oid);
4167  }
4168  }
4169  next_mop_toid = mop_toid->next;
4170  /*
4171  * Set mop to NULL before freeing the structure, so that it does not
4172  * become a GC root for this mop..
4173  */
4174  mop_toid->mop = NULL;
4175  free_and_init (mop_toid);
4176  mop_toid = next_mop_toid;
4177  }
4178  mflush->mop_toids = NULL;
4179 
4180  /* Notify the workspace about the changes that were made to objects belonging to partitioned classes. In the case
4181  * of a partition change, what the server returns here is a new object (not an updated one) and the object that
4182  * we sent was deleted */
4183  mop_toid = mflush->mop_uoids;
4184  while (mop_toid != NULL)
4185  {
4186  if (mop_toid->mop != NULL)
4187  {
4188  obj = LC_FIND_ONEOBJ_PTR_IN_COPYAREA (mflush->mobjs, mop_toid->obj);
4190 
4191  /* Check if object OID has changed */
4192  if (!OID_ISNULL (&obj->oid) && !OID_EQ (WS_OID (mop_toid->mop->class_mop), &obj->class_oid)
4193  && error_code == NO_ERROR)
4194  {
4195  error_code = ws_update_oid_and_class (mop_toid->mop, &obj->oid, &obj->class_oid);
4196  }
4197 
4198  /* Do not return in case of error. Allow the allocated memory to be freed first */
4199  }
4200 
4201  next_mop_toid = mop_toid->next;
4202 
4203  /*
4204  * Set mop to NULL before freeing the structure, so that it does not
4205  * become a GC root for this mop..
4206  */
4207  mop_toid->mop = NULL;
4208  free_and_init (mop_toid);
4209  mop_toid = next_mop_toid;
4210  }
4211  mflush->mop_uoids = NULL;
4212 
4213  for (i = 0; error_code == NO_ERROR && i < mflush->mobjs->num_objs; i++)
4214  {
4215  obj = LC_FIND_ONEOBJ_PTR_IN_COPYAREA (mflush->mobjs, i);
4216  if (OID_IS_ROOTOID (&obj->class_oid)
4217  && (obj->operation == LC_FLUSH_UPDATE || obj->operation == LC_FLUSH_UPDATE_PRUNE))
4218  {
4219  SM_CLASS *smclass = NULL;
4220  int save;
4221  MOP mop = ws_mop (&obj->oid, sm_Root_class_mop);
4222 
4223  AU_DISABLE (save);
4224  /* fetch to update catalog representation directory */
4225  error_code = au_fetch_class (mop, &smclass, AU_FETCH_READ, AU_SELECT);
4226  AU_ENABLE (save);
4227  }
4228  }
4229 
4230  if (error_code != NO_ERROR)
4231  {
4232  /*
4233  * There were problems forcing the objects.. Recover the objects..
4234  * Put them back into the workspace.. For example, some objects were
4235  * deleted from the workspace
4236  */
4237  for (i = 0; i < mflush->mobjs->num_objs; i++)
4238  {
4239  obj = LC_FIND_ONEOBJ_PTR_IN_COPYAREA (mflush->mobjs, i);
4240 
4241  if (error_code != NO_ERROR)
4242  {
4244  }
4245  }
4247  }
4248  }
4249 
4250  /* Now reset the flushing area... and continue flushing */
4251  locator_mflush_reset (mflush);
4252 
4253  return error_code;
4254 }
4255 
4256 /*
4257  * locator_class_to_disk () -
4258  *
4259  * return: error code
4260  *
4261  * mflush(in):
4262  * object(in):
4263  * has_index(out):
4264  * round_length_p(out):
4265  * map_status(out):
4266  *
4267  * Note: Place the object on the current remaining flushing area. If the
4268  * object does not fit. Force the area and try again
4269  */
4270 static int
4271 locator_class_to_disk (LOCATOR_MFLUSH_CACHE * mflush, MOBJ object, bool * has_index, int *round_length_p,
4272  WS_MAP_STATUS * map_status)
4273 {
4274  int error_code = NO_ERROR;
4275  TF_STATUS tfstatus;
4276  bool isalone;
4277  bool enable_class_to_disk;
4278 
4279  tfstatus = tf_class_to_disk (object, &mflush->recdes);
4280  if (tfstatus != TF_SUCCESS)
4281  {
4282  if (mflush->mobjs->num_objs == 0)
4283  {
4284  isalone = true;
4285  }
4286  else
4287  {
4288  isalone = false;
4289  }
4290 
4291  enable_class_to_disk = false;
4292  if (tfstatus != TF_ERROR)
4293  {
4294  if (isalone == true)
4295  {
4296  enable_class_to_disk = true;
4297  }
4298  else
4299  {
4300  error_code = locator_mflush_force (mflush);
4301  if (error_code == NO_ERROR)
4302  {
4303  enable_class_to_disk = true;
4304  }
4305  }
4306  }
4307 
4308  if (enable_class_to_disk)
4309  {
4310  /*
4311  * Quit after the above force. If only one flush is
4312  * desired and and we have flushed. stop
4313  */
4314  if (isalone == false && mflush->isone_mflush)
4315  { /* Don't do anything to current object */
4316  *map_status = WS_MAP_STOP;
4317  return ER_FAILED;
4318  }
4319 
4320  /* Try again */
4321  do
4322  {
4323  if (tfstatus == TF_ERROR)
4324  {
4325  /* There is an error of some sort. Stop.... */
4326  *map_status = WS_MAP_FAIL;
4327  return ER_FAILED;
4328  }
4329  /*
4330  * The object does not fit on flushing copy area.
4331  * Increase the size of the flushing area,
4332  * and try again.
4333  */
4334 
4335  *round_length_p = -mflush->recdes.length;
4336 
4337  /* reserve enough space for instances, since we can add additional MVCC header info at heap
4338  * insert/update/delete */
4339  *round_length_p += (OR_MVCC_MAX_HEADER_SIZE - OR_MVCC_INSERT_HEADER_SIZE);
4340 
4341  /*
4342  * If this is the only object in the flushing copy
4343  * area and does not fit even when the copy area seems
4344  * to be large enough, increase the copy area by at
4345  * least one page size.
4346  * This is done only for security purposes, since the
4347  * transformation class may not be given us the
4348  * correct length, somehow.
4349  */
4350 
4351  if (*round_length_p <= mflush->copy_area->length && isalone == true)
4352  {
4353  *round_length_p = mflush->copy_area->length + DB_PAGESIZE;
4354  }
4355 
4356  isalone = true;
4357 
4358  if (*round_length_p > mflush->copy_area->length
4359  && locator_mflush_reallocate_copy_area (mflush, *round_length_p) != NO_ERROR)
4360  {
4361  /* Out of memory space */
4362  *map_status = WS_MAP_FAIL;
4363  return ER_FAILED;
4364  }
4365 
4366  tfstatus = tf_class_to_disk (object, &mflush->recdes);
4367  }
4368  while (tfstatus != TF_SUCCESS);
4369  }
4370  else
4371  {
4372  *map_status = WS_MAP_FAIL;
4373  return ER_FAILED;
4374  }
4375  }
4376 
4377  return NO_ERROR;
4378 }
4379 
4380 /*
4381  * locator_mem_to_disk () -
4382  *
4383  * return: error code
4384  *
4385  * mflush(in):
4386  * object(in):
4387  * has_index(out):
4388  * round_length_p(out):
4389  * map_status(out):
4390  *
4391  * Note: Place the object on the current remaining flushing area. If the
4392  * object does not fit. Force the area and try again
4393  */
4394 static int
4395 locator_mem_to_disk (LOCATOR_MFLUSH_CACHE * mflush, MOBJ object, bool * has_index, int *round_length_p,
4396  WS_MAP_STATUS * map_status)
4397 {
4398  int error_code = NO_ERROR;
4399  TF_STATUS tfstatus;
4400  bool isalone;
4401  bool enable_mem_to_disk;
4402 
4403  tfstatus = tf_mem_to_disk (mflush->class_mop, mflush->class_obj, object, &mflush->recdes, has_index);
4404  if (tfstatus != TF_SUCCESS)
4405  {
4406  isalone = (mflush->mobjs->num_objs == 0) ? true : false;
4407 
4408  enable_mem_to_disk = false;
4409  if (tfstatus != TF_ERROR)
4410  {
4411  if (isalone == true)
4412  {
4413  enable_mem_to_disk = true;
4414  }
4415  else
4416  {
4417  error_code = locator_mflush_force (mflush);
4418  if (error_code == NO_ERROR)
4419  {
4420  enable_mem_to_disk = true;
4421  }
4422  }
4423  }
4424 
4425  if (enable_mem_to_disk)
4426  {
4427  /*
4428  * Quit after the above force. If only one flush is
4429  * desired and and we have flushed. stop
4430  */
4431  if (isalone == false && mflush->isone_mflush)
4432  { /* Don't do anything to current object */
4433  *map_status = WS_MAP_STOP;
4434  return ER_FAILED;
4435  }
4436 
4437  /* Try again */
4438  do
4439  {
4440  if (tfstatus == TF_ERROR)
4441  {
4442  /* There is an error of some sort. Stop.... */
4443  *map_status = WS_MAP_FAIL;
4444  return ER_FAILED;
4445  }
4446  /*
4447  * The object does not fit on flushing copy area.
4448  * Increase the size of the flushing area,
4449  * and try again.
4450  */
4451 
4452  *round_length_p = -mflush->recdes.length;
4453 
4454  /*
4455  * If this is the only object in the flushing copy
4456  * area and does not fit even when the copy area seems
4457  * to be large enough, increase the copy area by at
4458  * least one page size.
4459  * This is done only for security purposes, since the
4460  * transformation class may not be given us the
4461  * correct length, somehow.
4462  */
4463 
4464  if (*round_length_p <= mflush->copy_area->length && isalone == true)
4465  {
4466  *round_length_p = mflush->copy_area->length + DB_PAGESIZE;
4467  }
4468 
4469  isalone = true;
4470 
4471  if (*round_length_p > mflush->copy_area->length
4472  && locator_mflush_reallocate_copy_area (mflush, *round_length_p) != NO_ERROR)
4473  {
4474  /* Out of memory space */
4475  *map_status = WS_MAP_FAIL;
4476  return ER_FAILED;
4477  }
4478 
4479  tfstatus = tf_mem_to_disk (mflush->class_mop, mflush->class_obj, object, &mflush->recdes, has_index);
4480  }
4481  while (tfstatus != TF_SUCCESS);
4482  }
4483  else
4484  {
4485  *map_status = WS_MAP_FAIL;
4486  return ER_FAILED;
4487  }
4488  }
4489 
4490  return NO_ERROR;
4491 }
4492 
4493 /*
4494  * locator_mflush () - Prepare object for flushing
4495  *
4496  * return: either of WS_MAP_CONTINUE, WS_MAP_FAIL, or WS_MAP_STOP
4497  *
4498  * mop(in): Memory Object pointer of object to flush
4499  * mf(in): Multiple flush structure
4500  *
4501  * Note: Prepare the flushing of the object associated with the given
4502  * mop. The object is not currently flushed, instead it is placed
4503  * in a flushing area. When the flush area is full, then the area
4504  * is forced to server (the page buffer pool).
4505  */
4506 static int
4507 locator_mflush (MOP mop, void *mf)
4508 {
4509  int error_code = NO_ERROR;
4510  LOCATOR_MFLUSH_CACHE *mflush; /* Structure which describes objects to flush */
4511  HFID *hfid; /* Heap where the object is stored */
4512  OID *oid; /* Object identifier of object to flush */
4513  MOBJ object; /* The object to flush */
4514  MOP class_mop; /* The mop of the class of object to flush */
4515  int round_length; /* The length of the object in disk format rounded to alignments of size(int) */
4516  LC_COPYAREA_OPERATION operation; /* Flush operation to be executed: insert, update, delete, etc. */
4517  bool has_index; /* is an index maintained on the instances? */
4518  bool has_unique_index; /* is an unique maintained on the instances? */
4519  int status;
4520  bool decache;
4521  WS_MAP_STATUS map_status;
4523  int wasted_length;
4524 
4525  mflush = (LOCATOR_MFLUSH_CACHE *) mf;
4526 
4527  /* Flush the instance only if it is dirty */
4528  if (!WS_ISDIRTY (mop))
4529  {
4530  if (mflush->decache)
4531  {
4532  (void) sm_decache_mop (mop, NULL);
4533  }
4534 
4535  return WS_MAP_CONTINUE;
4536  }
4537 
4538  if (WS_ISPINNED (mop))
4539  {
4540  /* Since dirty bit can't be reset during flush, if the object is pinned, we need to check if pinned mop is
4541  * already in flush area. We need to avoid adding the same mop twice. */
4542  operation = LC_UPDATE_OPERATION_TYPE (mop->pruning_type);
4543  if (LC_IS_FLUSH_INSERT (operation) && OID_ISTEMP (ws_oid (mop)))
4544  {
4545  LOCATOR_MFLUSH_TEMP_OID *mop_toid;
4546  for (mop_toid = mflush->mop_toids; mop_toid != NULL; mop_toid = mop_toid->next)
4547  {
4548  if (mop_toid->mop == mop)
4549  {
4550  /* already in flush area */
4551  return WS_MAP_CONTINUE;
4552  }
4553  }
4554  }
4555  else if (operation == LC_FLUSH_UPDATE_PRUNE
4556  || (operation == LC_FLUSH_UPDATE && ws_class_mop (mop) != sm_Root_class_mop))
4557  {
4558  LOCATOR_MFLUSH_TEMP_OID *mop_uoid;
4559  for (mop_uoid = mflush->mop_uoids; mop_uoid != NULL; mop_uoid = mop_uoid->next)
4560  {
4561  if (ws_is_same_object (mop_uoid->mop, mop))
4562  {
4563  /* already in flush area */
4564  return WS_MAP_CONTINUE;
4565  }
4566  }
4567  }
4568  }
4569 
4570  /* Check if this is a virtual ID */
4571 
4572  if (WS_ISVID (mop))
4573  {
4574  return vid_flush_instance (mop, NULL);
4575  }
4576 
4577  oid = ws_oid (mop);
4578 
4579 #if defined(CUBRID_DEBUG)
4580  if (OID_ISNULL (oid))
4581  {
4583  "locator_mflush: SYSTEM ERROR OID %d|%d|%d in the workspace is a NULL_OID. It cannot be...\n",
4584  oid->volid, oid->pageid, oid->slotid);
4585  return WS_MAP_FAIL;
4586  }
4587 #endif /* CUBRID_DEBUG */
4588 
4589  class_mop = ws_class_mop (mop);
4590  if (class_mop == NULL || class_mop->object == NULL)
4591  {
4593  oid->slotid);
4594 #if defined(CUBRID_DEBUG)
4596  "locator_mflush: SYSTEM ERROR Unable to flush.\n Workspace does not know class_mop for object "
4597  "OID %d|%d|%d\n", oid->volid, oid->pageid, oid->slotid);
4598 #endif /* CUBRID_DEBUG */
4599  return WS_MAP_FAIL;
4600  }
4601 
4602  if (WS_ISDIRTY (class_mop) && class_mop != mop)
4603  {
4604  /*
4605  * Make sure that the class is not decached.. otherwise, we may have
4606  * problems
4607  */
4608  decache = mflush->decache;
4609  mflush->decache = false;
4610  if (WS_IS_DELETED (class_mop))
4611  {
4612  status = locator_mflush (class_mop, mf);
4613  mflush->decache = decache;
4614  return status;
4615  }
4616  else
4617  {
4618  status = locator_mflush (class_mop, mf);
4619  if (status != WS_MAP_CONTINUE)
4620  {
4621  mflush->decache = decache;
4622  return status;
4623  }
4624  mflush->decache = decache;
4625  }
4626  }
4627 
4628  if (class_mop->lock < IX_LOCK)
4629  {
4630  /* place correct lock on class object, we might not have it yet */
4632  {
4633  return WS_MAP_FAIL;
4634  }
4635  }
4636 
4637  if (ws_find (mop, &object) == WS_FIND_MOP_DELETED)
4638  {
4639  /* Delete operation */
4640 
4641  if (OID_ISTEMP (oid))
4642  {
4643  /* if this is a new object (i.e., it has not been flushed), we only need to decache the object. */
4644  ws_decache (mop);
4645  return WS_MAP_CONTINUE;
4646  }
4647 
4648  operation = LC_FLUSH_DELETE;
4649  mflush->recdes.length = 0;
4650 
4651  /* Find the heap where the object is stored */
4652  /* Is the object a class ? */
4653  if (locator_is_root (class_mop))
4654  {
4655  hfid = sm_Root_class_hfid;
4656  has_index = false;
4657  has_unique_index = false;
4658  }
4659  else
4660  {
4661  /* Assume that there is an index for the object */
4662  has_index = true;
4663  /* The object is an instance */
4664  if (class_mop != mflush->class_mop)
4665  {
4666  /* Find the class for the current object */
4668  if (mflush->class_obj == NULL)
4669  {
4670  mflush->class_mop = NULL;
4671  return WS_MAP_FAIL;
4672  }
4673 
4674  /* Cache this information for future flushes */
4675  mflush->class_mop = class_mop;
4676  mflush->hfid = sm_ch_heap (mflush->class_obj);
4677  }
4678  hfid = mflush->hfid;
4679  has_index = sm_has_indexes (mflush->class_obj);
4680  error_code = sm_class_has_unique_constraint (mflush->class_obj, NULL, true, &has_unique_index);
4681  if (error_code != NO_ERROR)
4682  {
4683  return WS_MAP_FAIL;
4684  }
4685  }
4686  }
4687  else if (object == NULL)
4688  {
4689  /* We have the object. This is an insertion or an update operation */
4691 #if defined(CUBRID_DEBUG)
4693  "locator_mflush: SYSTEM ERROR, The MOP of object OID %d|%d|%d is dirty, is not marked as\n"
4694  " deleted and does not have the object\n", oid->volid, oid->pageid, oid->slotid);
4695 #endif /* CUBRID_DEBUG */
4696  return WS_MAP_FAIL;
4697  }
4698  else
4699  {
4700  error_code = sm_partitioned_class_type (class_mop, &class_type, NULL, NULL);
4701  if (error_code != NO_ERROR)
4702  {
4703  return WS_MAP_FAIL;
4704  }
4705  if (class_type != DB_NOT_PARTITIONED_CLASS)
4706  {
4707  /* sanity check: make sure we don't flush an instance of a partitioned class without pruning */
4709  {
4710  /* At this point, we can't decide how the user intended to work with this object so we must assume we're
4711  * working with the partitioned class */
4713  }
4714  }
4715  if (OID_ISTEMP (oid))
4716  {
4717  operation = LC_INSERT_OPERATION_TYPE (mop->pruning_type);
4718  }
4719  else
4720  {
4721  operation = LC_UPDATE_OPERATION_TYPE (mop->pruning_type);
4722  }
4723 
4724  /* Is the object a class ? */
4725  if (locator_is_root (class_mop))
4726  {
4727  has_index = false;
4728  has_unique_index = false;
4729  if (locator_class_to_disk (mflush, object, &has_index, &round_length, &map_status) != NO_ERROR)
4730  {
4731  return map_status;
4732  }
4733  hfid = sm_Root_class_hfid;
4734  }
4735  else
4736  {
4737  /* The object is an instance */
4738  /* Find the class of the current instance */
4739 
4740  if (class_mop != mflush->class_mop)
4741  {
4742  /* Find the class for the current object */
4744  if (mflush->class_obj == NULL)
4745  {
4746  mflush->class_mop = NULL;
4747  return WS_MAP_FAIL;
4748  }
4749  /* Cache this information for future flushes */
4750  mflush->class_mop = class_mop;
4751  mflush->hfid = sm_ch_heap (mflush->class_obj);
4752  }
4753 
4754  if (locator_mem_to_disk (mflush, object, &has_index, &round_length, &map_status) != NO_ERROR)
4755  {
4756  return map_status;
4757  }
4758  hfid = mflush->hfid;
4759  error_code = sm_class_has_unique_constraint (mflush->class_obj, NULL, true, &has_unique_index);
4760  if (error_code != NO_ERROR)
4761  {
4762  return WS_MAP_FAIL;
4763  }
4764  }
4765  }
4766 
4767  if (mflush->decache || operation == LC_FLUSH_DELETE)
4768  {
4769  ws_decache (mop);
4770  }
4771  else
4772  {
4773  ws_clean (mop);
4774  }
4775 
4776  /* Now update the mflush structure */
4777 
4778  if (LC_IS_FLUSH_INSERT (operation))
4779  {
4780  /*
4781  * For new objects, make sure that its OID is still a temporary
4782  * one. If it is not, a permanent OID was assigned during the
4783  * transformation process, likely the object points to itself
4784  */
4785  if (OID_ISTEMP (ws_oid (mop)))
4786  {
4787  LOCATOR_MFLUSH_TEMP_OID *mop_toid;
4788 
4789  mop_toid = (LOCATOR_MFLUSH_TEMP_OID *) malloc (sizeof (*mop_toid));
4790  if (mop_toid == NULL)
4791  {
4793  return WS_MAP_FAIL;
4794  }
4795 
4796  assert (mflush->mop_tail_toid != mop);
4797 
4798  if (mflush->mop_tail_toid == NULL)
4799  {
4800  mflush->mop_tail_toid = mop;
4801  }
4802 
4803  mop_toid->mop = mop;
4804  mop_toid->obj = mflush->mobjs->num_objs;
4805  mop_toid->next = mflush->mop_toids;
4806  mflush->mop_toids = mop_toid;
4807  }
4808  else
4809  {
4810  if (operation == LC_FLUSH_INSERT)
4811  {
4812  operation = LC_FLUSH_UPDATE;
4813  }
4814  else if (operation == LC_FLUSH_INSERT_PRUNE)
4815  {
4816  operation = LC_FLUSH_UPDATE_PRUNE;
4817  }
4818  else
4819  {
4820  operation = LC_FLUSH_UPDATE_PRUNE_VERIFY;
4821  }
4822 
4823  oid = ws_oid (mop);
4824  }
4825  }
4826  else if (operation == LC_FLUSH_UPDATE_PRUNE)
4827  {
4828  /* We have to keep track of updated objects from partitioned classes. If this object will be moved in another
4829  * partition we have to mark it like this (a delete/insert operation). This means that the current mop will be
4830  * deleted and the partition that received this object will have a new mop in its obj list. */
4831  /* Another case when OID can change is MVCC update on instances (MVCC is disabled for classes. */
4832  LOCATOR_MFLUSH_TEMP_OID *mop_uoid;
4833 
4834  mop_uoid = (LOCATOR_MFLUSH_TEMP_OID *) malloc (sizeof (*mop_uoid));
4835  if (mop_uoid == NULL)
4836  {
4838  return WS_MAP_FAIL;
4839  }
4840 
4841  assert (mflush->mop_tail_uoid != mop);
4842 
4843  if (mflush->mop_tail_uoid == NULL)
4844  {
4845  mflush->mop_tail_uoid = mop;
4846  }
4847 
4848  mop_uoid->mop = mop;
4849  mop_uoid->obj = mflush->mobjs->num_objs;
4850  mop_uoid->next = mflush->mop_uoids;
4851  mflush->mop_uoids = mop_uoid;
4852  }
4853 
4854  if (HFID_IS_NULL (hfid))
4855  {
4856  /*
4857  * There is not place to store the object. This is an error, the heap
4858  * should have been allocated when the object was created
4859  */
4861  return WS_MAP_FAIL;
4862  }
4863 
4864  mflush->mobjs->num_objs++;
4865  mflush->obj->operation = operation;
4866 
4867  /* init object flag */
4868  mflush->obj->flag = 0;
4869 
4870  /* set has index */
4871  if (has_index)
4872  {
4873  LC_ONEOBJ_SET_HAS_INDEX (mflush->obj);
4874  }
4875 
4876  if (has_unique_index)
4877  {
4879  }
4880 
4881  HFID_COPY (&mflush->obj->hfid, hfid);
4882  COPY_OID (&mflush->obj->class_oid, ws_oid (class_mop));
4883  COPY_OID (&mflush->obj->oid, oid);
4884  if (operation == LC_FLUSH_DELETE)
4885  {
4886  mflush->obj->length = -1;
4887  mflush->obj->offset = -1;
4888  round_length = 0;
4889  }
4890  else
4891  {
4892  round_length = mflush->recdes.length;
4893  mflush->obj->length = mflush->recdes.length;
4894  mflush->obj->offset = CAST_BUFLEN (mflush->recdes.data - mflush->copy_area->mem);
4895  }
4896 
4897  mflush->obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (mflush->obj);
4898 
4899  /*
4900  * Round the length of the object, so that new placement of objects
4901  * start at alignment of sizeof(int)
4902  */
4903 
4904  if (!locator_is_root (class_mop))
4905  {
4906  /* reserve enough space for instances, since we can add additional MVCC header info at heap insert/update/delete */
4908  }
4909 
4910  wasted_length = DB_WASTED_ALIGN (round_length, MAX_ALIGNMENT);
4911 
4912 #if !defined (NDEBUG)
4913  if (round_length < mflush->recdes.area_size)
4914  {
4915  /* suppress valgrind UMW error */
4916  size_t hole_size;
4917 
4918  hole_size = MIN (wasted_length, mflush->recdes.area_size - round_length);
4919  if (0 < hole_size)
4920  {
4921  memset (mflush->recdes.data + round_length, 0, hole_size);
4922  }
4923  }
4924 #endif
4925 
4926  round_length = round_length + wasted_length;
4927  mflush->recdes.data += round_length;
4928  mflush->recdes.area_size -= round_length + sizeof (*(mflush->obj));
4929 
4930  /* If there is not any more area, force the area */
4931  if (mflush->recdes.area_size <= 0)
4932  {
4933  /* Force the mflush area */
4934  error_code = locator_mflush_force (mflush);
4935  if (error_code != NO_ERROR)
4936  {
4937  return WS_MAP_FAIL;
4938  }
4939  }
4940 
4941  return WS_MAP_CONTINUE;
4942 }
4943 
4944 /*
4945  * locator_repl_mflush () - place repl objects into LOCATOR_MFLUSH_CACHE
4946  *
4947  * return: error code
4948  *
4949  * mflush(in/out): copy area contents and descriptors
4950  */
4951 static int
4953 {
4954  int error = NO_ERROR;
4955  WS_REPL_OBJ *repl_obj;
4956  int required_length;
4957  int key_length, round_length, wasted_length;
4958  char *ptr, *obj_start_p;
4959 
4960  while (true)
4961  {
4962  repl_obj = ws_get_repl_obj_from_list ();
4963  if (repl_obj == NULL)
4964  {
4965  break;
4966  }
4967 
4968  /* includes leading and trailing alignment */
4969  required_length = repl_obj->packed_pkey_value_length + MAX_ALIGNMENT + INT_ALIGNMENT;
4970  if (repl_obj->operation != LC_FLUSH_DELETE)
4971  {
4972  assert (repl_obj->recdes != NULL && repl_obj->recdes->data != NULL);
4973  required_length += repl_obj->recdes->length + MAX_ALIGNMENT;
4974  }
4975 
4976  while (mflush->recdes.area_size < required_length)
4977  {
4978  if (mflush->mobjs->num_objs == 0)
4979  {
4980  error = locator_mflush_reallocate_copy_area (mflush, required_length + DB_SIZEOF (LC_COPYAREA_MANYOBJS));
4981  if (error != NO_ERROR)
4982  {
4983  return error;
4984  }
4985  }
4986  else
4987  {
4988  error = locator_repl_mflush_force (mflush);
4989  if (error != NO_ERROR && error != ER_LC_PARTIALLY_FAILED_TO_FLUSH)
4990  {
4991  return error;
4992  }
4993  }
4994  }
4995 
4996  /* put packed key_value and recdes in copy_area */
4997 
4998  /* put packed key_value first */
4999  obj_start_p = ptr = mflush->recdes.data;
5000 
5001  ptr = PTR_ALIGN (ptr, MAX_ALIGNMENT); /* 8 bytes alignment. see or_pack_mem_value */
5002 
5003  memcpy (ptr, repl_obj->packed_pkey_value, repl_obj->packed_pkey_value_length);
5004  ptr += repl_obj->packed_pkey_value_length;
5005 
5006  ptr = PTR_ALIGN (ptr, INT_ALIGNMENT); /* for int alignment. see or_pack_mem_value */
5007 
5008  key_length = CAST_BUFLEN (ptr - obj_start_p);
5009  mflush->recdes.data = ptr;
5010 
5011  if (repl_obj->operation == LC_FLUSH_DELETE)
5012  {
5013  assert (repl_obj->recdes == NULL);
5014  mflush->recdes.length = 0;
5015  }
5016  else
5017  {
5018  assert (repl_obj->recdes->data != NULL);
5019 
5020  memcpy (mflush->recdes.data, repl_obj->recdes->data, repl_obj->recdes->length);
5021  mflush->recdes.length = repl_obj->recdes->length;
5022  }
5023 
5024  mflush->mobjs->num_objs++;
5025  mflush->obj->operation = (LC_COPYAREA_OPERATION) repl_obj->operation;
5026  if (repl_obj->has_index == true)
5027  {
5028  LC_ONEOBJ_SET_HAS_INDEX (mflush->obj);
5029  }
5030 
5031  COPY_OID (&mflush->obj->class_oid, &repl_obj->class_oid);
5032  HFID_SET_NULL (&mflush->obj->hfid);
5033  OID_SET_NULL (&mflush->obj->oid);
5034 
5035  mflush->obj->length = mflush->recdes.length + key_length;
5036  mflush->obj->offset = CAST_BUFLEN (obj_start_p - mflush->copy_area->mem);
5037 
5038  wasted_length = DB_WASTED_ALIGN (mflush->obj->length, MAX_ALIGNMENT);
5039 #if !defined(NDEBUG)
5040  /* suppress valgrind UMW error */
5041  memset (obj_start_p + mflush->obj->length, 0,
5042  MIN (wasted_length, mflush->recdes.area_size - mflush->obj->length));
5043 #endif
5044  round_length = mflush->obj->length + wasted_length;
5045  mflush->recdes.data = obj_start_p + round_length;
5046  mflush->recdes.area_size -= round_length + sizeof (*(mflush->obj));
5047 
5048  mflush->obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (mflush->obj);
5049  ws_free_repl_obj (repl_obj);
5050  }
5051 
5052  return error;
5053 }
5054 
5055 /*
5056  * locator_flush_class () - Flush a dirty class
5057  *
5058  * return: NO_ERROR if all OK, ER status otherwise
5059  *
5060  * class_mop(in): Mop of class to flush
5061  *
5062  * Note: The class associated with the given mop is flushed to the page
5063  * buffer pool (server). Other dirty objects may be flushed along
5064  * with the class. Generally, a flushing area (page) of dirty
5065  * objects is sent to the server.
5066  */
5067 int
5069 {
5070  LOCATOR_MFLUSH_CACHE mflush; /* Structure which describes objects to flush */
5071  MOBJ class_obj;
5072  int error_code = NO_ERROR;
5073  int map_status = WS_MAP_FAIL;
5074 
5075  if (class_mop == NULL)
5076  {
5078  return ER_OBJ_INVALID_ARGUMENTS;
5079  }
5080 
5081  if (WS_ISDIRTY (class_mop) && (ws_find (class_mop, &class_obj) == WS_FIND_MOP_DELETED || class_obj != NULL))
5082  {
5083  /*
5084  * Prepare the area for flushing... only one force area
5085  * Flush class and preflush other dirty objects to the flushing area
5086  */
5087  error_code = locator_mflush_initialize (&mflush, NULL, NULL, NULL, DONT_DECACHE, ONE_MFLUSH);
5088  if (error_code == NO_ERROR)
5089  {
5090  /* current class mop flush */
5091  map_status = locator_mflush (class_mop, &mflush);
5092  if (map_status == WS_MAP_CONTINUE)
5093  {
5094  map_status = ws_map_dirty (locator_mflush, &mflush);
5095  if (map_status == WS_MAP_SUCCESS)
5096  {
5097  if (mflush.mobjs->num_objs != 0)
5098  {
5099  error_code = locator_mflush_force (&mflush);
5100  }
5101  }
5102  }
5103  if (map_status == WS_MAP_FAIL)
5104  {
5105  error_code = ER_FAILED;
5106  }
5107  locator_mflush_end (&mflush);
5108  }
5109  }
5110 
5111  if (error_code != NO_ERROR && er_errid () == NO_ERROR)
5112  {
5114  }
5115 
5116  return error_code;
5117 }
5118 
5119 /*
5120  * locator_internal_flush_instance () - Flush a dirty instance and optionally
5121  * decache it
5122  *
5123  * return: NO_ERROR if all OK, ER status otherwise
5124  *
5125  * inst_mop(in): Mop of instance to flush
5126  * decache(in): true if it needs to be decached, otherwise, false
5127  *
5128  * Note: The instance associated with the given mop is flushed to the
5129  * page buffer pool (server). Other dirty objects may be flushed
5130  * along with the given instance. Generally, a flushing area
5131  * (page) of dirty objects is sent to the server.
5132  * The instance is also decached when requested.
5133  */
5134 static int
5135 locator_internal_flush_instance (MOP inst_mop, bool decache)
5136 {
5137  LOCATOR_MFLUSH_CACHE mflush; /* Structure which describes objects to flush */
5138  MOBJ inst;
5139  int map_status;
5140  int error_code = NO_ERROR;
5141  int retry_count = 0;
5142  int chn;
5143 
5144  if (inst_mop == NULL)
5145  {
5147  return ER_OBJ_INVALID_ARGUMENTS;
5148  }
5149 
5150 retry:
5151  if (WS_ISDIRTY (inst_mop) && (ws_find (inst_mop, &inst) == WS_FIND_MOP_DELETED || inst != NULL))
5152  {
5153  /*
5154  * Prepare the area for flushing... only one force area
5155  * Flush instance and preflush other dirty objects to the flushing area
5156  */
5157  if (inst != NULL)
5158  {
5159  chn = WS_CHN (inst);
5160  }
5161  else
5162  {
5163  chn = CHN_UNKNOWN_ATCLIENT;
5164  }
5165  error_code = locator_mflush_initialize (&mflush, NULL, NULL, NULL, decache, ONE_MFLUSH);
5166  if (error_code == NO_ERROR)
5167  {
5168  /* current instance mop flush */
5169  map_status = locator_mflush (inst_mop, &mflush);
5170  if (map_status == WS_MAP_CONTINUE)
5171  {
5172  map_status = ws_map_dirty (locator_mflush, &mflush);
5173  if (map_status == WS_MAP_SUCCESS)
5174  {
5175  if (mflush.mobjs->num_objs != 0)
5176  {
5177  error_code = locator_mflush_force (&mflush);
5178  if (error_code == NO_ERROR && chn != CHN_UNKNOWN_ATCLIENT && chn == WS_CHN (inst))
5179  {
5180  locator_mflush_end (&mflush);
5181  /*
5182  * Make sure that you don't loop more than
5183  * once in this function.
5184  */
5185  if (retry_count < 2)
5186  {
5187  retry_count++;
5188  goto retry;
5189  }
5190  }
5191  }
5192  }
5193  }
5194 
5195  if (map_status == WS_MAP_FAIL)
5196  {
5197  error_code = ER_FAILED;
5198  }
5199 
5200  locator_mflush_end (&mflush);
5201  }
5202  }
5203  else if (decache == true)
5204  {
5205  ws_decache (inst_mop);
5206  }
5207 
5208  if (error_code != NO_ERROR && er_errid () == NO_ERROR)
5209  {
5211  }
5212 
5213  if (error_code == NO_ERROR && retry_count > 1)
5214  {
5215  er_log_debug (ARG_FILE_LINE, "Flush failed after two retries");
5217  error_code = ER_GENERIC_ERROR;
5218  }
5219 
5220  return error_code;
5221 }
5222 
5223 /*
5224  * locator_flush_instance () - Flush a dirty instance
5225  *
5226  * return: NO_ERROR if all OK, ER status otherwise
5227  *
5228  * mop(in): Mop of instance to flush
5229  *
5230  * Note: The instance associated with the given mop is flushed to the
5231  * page buffer pool (server). Other dirty objects may be flushed
5232  * along with the given instance. Generally, a flushing area
5233  * (page) of dirty objects is sent to the server.
5234  */
5235 int
5237 {
5239 }
5240 
5241 #if defined (ENABLE_UNUSED_FUNCTION)
5242 /*
5243  * locator_flush_and_decache_instance () - Flush a dirty instance and decache it
5244  *
5245  * return: NO_ERROR if all OK, ER status otherwise
5246  *
5247  * mop(in): Mop of instance to flush
5248  *
5249  * Note: The instance associated with the given mop is flushed to the
5250  * page buffer pool (server) when dirty. The instance is also
5251  * decached from the workspace.
5252  * Other dirty objects may be flushed along with the given
5253  * instance. Generally, a flushing area (page) of dirty objects
5254  * is sent to the server.
5255  */
5256 int
5257 locator_flush_and_decache_instance (MOP mop)
5258 {
5260 }
5261 #endif /* ENABLE_UNUSED_FUNCTION */
5262 
5263 /*
5264  * locator_flush_all_instances () - Flush dirty instances of a class
5265  *
5266  * return: NO_ERROR if all OK, ER status otherwise
5267  *
5268  * class_mop(in): The class mop of the instances to flush
5269  * decache(in): true, if instances must be decached after they are
5270  * flushed.
5271  *
5272  * Note: Flush all dirty instances of the class associated with the
5273  * given class_mop to the page buffer pool (server). In addition,
5274  * if the value of decache is true, all instances (whether or
5275  * not they are dirty) of the class are decached.
5276  */
5277 int
5278 locator_flush_all_instances (MOP class_mop, bool decache)
5279 {
5280  LOCATOR_MFLUSH_CACHE mflush; /* Structure which describes objects to flush */
5281  MOBJ class_obj; /* The class object */
5282  HFID *hfid; /* Heap where the instances of class_mop are stored */
5283  int error_code = NO_ERROR;
5284  int map_status;
5285  DB_OBJLIST class_list;
5286  DB_OBJLIST *obj = NULL;
5287  bool is_partitioned = false;
5288 
5289  if (class_mop == NULL)
5290  {
5291  return ER_FAILED;
5292  }
5293 
5294  class_obj = locator_fetch_class (class_mop, DB_FETCH_READ);
5295  if (class_obj == NULL)
5296  {
5297  return ER_FAILED;
5298  }
5299 
5300  if (WS_ISVID (class_mop))
5301  {
5302  return vid_flush_all_instances (class_mop, decache);
5303  }
5304 
5305  class_list.op = class_mop;
5306  class_list.next = NULL;
5307 
5308  if (!locator_is_root (class_mop))
5309  {
5310  SM_CLASS *class_ = (SM_CLASS *) class_obj;
5311  if (class_->partition != NULL && class_->users != NULL)
5312  {
5313  is_partitioned = true;
5314  class_list.next = class_->users;
5315  }
5316  }
5317 
5318  if (is_partitioned)
5319  {
5320  /* This is a partitioned class. Also flush instances belonging to partitions. */
5321  error_code = locator_mflush_initialize (&mflush, NULL, NULL, NULL, decache, MANY_MFLUSHES);
5322  if (error_code != NO_ERROR)
5323  {
5324  return error_code;
5325  }
5326  }
5327  else
5328  {
5329  hfid = sm_ch_heap (class_obj);
5330  error_code = locator_mflush_initialize (&mflush, class_mop, class_obj, hfid, decache, MANY_MFLUSHES);
5331  if (error_code != NO_ERROR)
5332  {
5333  return error_code;
5334  }
5335  }
5336 
5337  /* Iterate through classes and flush only those which have been loaded into the workspace. */
5338  for (obj = &class_list; obj != NULL && error_code == NO_ERROR; obj = obj->next)
5339  {
5340  if (obj->op == NULL || obj->op->object == NULL)
5341  {
5342  /* This class is not in the workspace, skip it */
5343  continue;
5344  }
5345 
5346  if (decache)
5347  {
5348  /* decache all instances of this class */
5349  map_status = ws_map_class (obj->op, locator_mflush, &mflush);
5350  }
5351  else
5352  {
5353  /* flush all dirty instances of this class */
5354  map_status = ws_map_class_dirty (obj->op, locator_mflush, &mflush);
5355  }
5356 
5357  if (map_status == WS_MAP_FAIL)
5358  {
5359  ASSERT_ERROR_AND_SET (error_code);
5360  }
5361  }
5362 
5363  if (mflush.mobjs->num_objs != 0)
5364  {
5365  error_code = locator_mflush_force (&mflush);
5366  }
5367 
5368  locator_mflush_end (&mflush);
5369 
5370  if (error_code != NO_ERROR)
5371  {
5372  return error_code;
5373  }
5374 
5375  if (decache)
5376  {
5377  for (obj = &class_list; obj != NULL; obj = obj->next)
5378  {
5380  }
5381  }
5382 
5383  return error_code;
5384 }
5385 
5386 /*
5387  * locator_flush_for_multi_update () -
5388  *
5389  * return: NO_ERROR if all OK, ER status otherwise
5390  *
5391  * class_mop(in):
5392  *
5393  * Note:This function is for flushing the updated objects
5394  * in case of multiple row update performed on client.
5395  * All flush request messages made by this function have
5396  * useful values in start_multi_update, end_multi_update,
5397  * class_oid fields.
5398  * Other flush request messages have NULL class OID value.
5399  */
5400 int
5402 {
5403  LOCATOR_MFLUSH_CACHE mflush; /* Structure which describes objects to flush */
5404  MOBJ class_obj; /* The class object */
5405  HFID *hfid; /* Heap where the instances of class_mop are stored */
5406  int error_code = NO_ERROR;
5407  int map_status;
5408 
5409  class_obj = locator_fetch_class (class_mop, DB_FETCH_READ);
5410  if (class_obj == NULL)
5411  {
5412  error_code = ER_FAILED;
5413  goto error;
5414  }
5415 
5416  hfid = sm_ch_heap (class_obj);
5417  /* The fifth argument, decache, is false. */
5418  locator_mflush_initialize (&mflush, class_mop, class_obj, hfid, false, MANY_MFLUSHES);
5419  if (error_code != NO_ERROR)
5420  {
5421  goto error;
5422  }
5423 
5424  /* special code for uniqueness checking */
5427 
5428  /* flush all dirty instances of this class */
5429  map_status = ws_map_class_dirty (class_mop, locator_mflush, &mflush);
5430 
5431  if (map_status == WS_MAP_SUCCESS)
5432  {
5433  /* Even if mflush.mobjs->num_objs == 0, invoke locator_mflush_force() to indicate the end of multiple updates. */
5435  error_code = locator_mflush_force (&mflush);
5436  }
5437 
5438  if (map_status == WS_MAP_FAIL)
5439  {
5440  error_code = ER_FAILED;
5441  }
5442 
5443  locator_mflush_end (&mflush);
5444 
5445 error:
5446  return error_code;
5447 }
5448 
5449 /*
5450  * locator_all_flush () - Flush all dirty objects
5451  *
5452  * return: NO_ERROR if all OK, ER status otherwise
5453  *
5454  * Note: Form to flush all dirty objects to the page buffer pool (server).
5455  */
5456 int
5458 {
5459  LOCATOR_MFLUSH_CACHE mflush; /* Structure which describes objects to flush */
5460  int error_code;
5461  int map_status;
5462 
5463  /* flush dirty vclass objects */
5464  if (vid_allflush () != NO_ERROR)
5465  {
5466  return ER_FAILED;
5467  }
5468 
5469  /* flush all other dirty objects */
5470  error_code = locator_mflush_initialize (&mflush, NULL, NULL, NULL, DONT_DECACHE, MANY_MFLUSHES);
5471  if (error_code != NO_ERROR)
5472  {
5473  return error_code;
5474  }
5475 
5476  map_status = ws_map_dirty (locator_mflush, &mflush);
5477  if (map_status == WS_MAP_FAIL)
5478  {
5479  error_code = ER_FAILED;
5480  }
5481  else if (map_status == WS_MAP_SUCCESS)
5482  {
5483  if (mflush.mobjs->num_objs != 0)
5484  {
5485  error_code = locator_mflush_force (&mflush);
5486  }
5487  }
5488 
5489  locator_mflush_end (&mflush);
5490 
5491  return error_code;
5492 }
5493 
5494 /*
5495  * locator_repl_flush_all () - flush all repl objects
5496  *
5497  * return: error code
5498  */
5499 int
5501 {
5502  LOCATOR_MFLUSH_CACHE mflush;
5503  int error;
5504  bool continued_on_error = false;
5505 
5507  if (error != NO_ERROR)
5508  {
5509  return error;
5510  }
5511 
5512  error = locator_repl_mflush (&mflush);
5513  if (error == ER_LC_PARTIALLY_FAILED_TO_FLUSH)
5514  {
5515  continued_on_error = true;
5516  }
5517  else if (error != NO_ERROR)
5518  {
5519  return error;
5520  }
5521 
5522  error = locator_repl_mflush_force (&mflush);
5523  if (error == NO_ERROR && continued_on_error == true)
5524  {
5526  }
5527 
5528  locator_mflush_end (&mflush);
5529 
5530  return error;
5531 }
5532 
5533 /*
5534  * locator_add_root () - Insert root
5535  *
5536  * return:MOP
5537  *
5538  * root_oid(in): Root oid
5539  * class_root(in): Root object
5540  *
5541  * Note: Add the root class. Used only when the database is created.
5542  */
5543 MOP
5544 locator_add_root (OID * root_oid, MOBJ class_root)
5545 {
5546  MOP root_mop; /* Mop of the root */
5547 
5548  /*
5549  * Insert the root class, set it dirty and cache the lock.. we need to cache
5550  * the lock since it was not acquired directly. Actually, it has not been
5551  * requested. It is set when the root class is flushed
5552  */
5553 
5554  /* Find a mop */
5555  root_mop = ws_mop (root_oid, NULL);
5556  if (root_mop == NULL)
5557  {
5558  return NULL;
5559  }
5560 
5561  ws_cache (class_root, root_mop, root_mop);
5562  ws_dirty (root_mop);
5563  ws_set_lock (root_mop, SCH_M_LOCK);
5564 
5565  sm_Root_class_mop = root_mop;
5566  oid_Root_class_oid = ws_oid (root_mop);
5567 
5568  /* Reserve the class name */
5570  || locator_flush_class (root_mop) != NO_ERROR)
5571  {
5572  root_mop = NULL;
5573  }
5574 
5576 
5577  return root_mop;
5578 }
5579 
5580 /*
5581  * locator_add_class () - Insert a class
5582  *
5583  * return: MOP
5584  *
5585  * class(in): Class object to add onto the database
5586  * classname(in): Name of the class
5587  *
5588  * Note: Add a class onto the database. Neither the permanent OID for
5589  * the newly created class nor a lock on the class are assigned
5590  * at this moment. Both the lock and its OID are acquired when
5591  * the class is flushed to the server (page buffer pool)
5592  * Only an IX lock is acquired on the root class.
5593  */
5594 MOP
5595 locator_add_class (MOBJ class_obj, const char *classname)
5596 {
5597  OID class_temp_oid; /* A temporarily OID for the newly created class */
5598  MOP class_mop; /* The Mop of the newly created class */
5599  LOCK lock;
5600 
5601  if (classname == NULL)
5602  {
5603  return NULL;
5604  }
5605 
5606  class_mop = ws_find_class (classname);
5607  if (class_mop != NULL && ws_get_lock (class_mop) != NULL_LOCK)
5608  {
5609  if (!WS_IS_DELETED (class_mop))
5610  {
5611  /* The class already exist.. since it is cached */
5613  return NULL;
5614  }
5615 
5616  /*
5617  * Flush the deleted class so we do not have problems with the
5618  * classname to oid entry during commit
5619  */
5620  if (locator_flush_class (class_mop) != NO_ERROR)
5621  {
5622  return NULL;
5623  }
5624  }
5625 
5626  /*
5627  * Class name should be already reserved, and server generated a pseudo-oid
5628  * for it. Get the OID.
5629  */
5630 
5631  if (locator_get_reserved_class_name_oid (classname, &class_temp_oid) != NO_ERROR)
5632  {
5633  return NULL;
5634  }
5635 
5636  /*
5637  * SCH_M_LOCK and IX_LOCK locks were indirectly acquired on the newly
5638  * created class and the root class using the locator_reserve_class_name
5639  * function.
5640  */
5641 
5642  /*
5643  * If there is any lock on the sm_Root_class_mop, its lock is converted to
5644  * reflect the IX_LOCK. Otherwise, the root class is fetched to synchronize
5645  * the root
5646  */
5647 
5648  lock = ws_get_lock (sm_Root_class_mop);
5649  if (lock != NULL_LOCK)
5650  {
5651  assert (lock >= NULL_LOCK);
5652  lock = lock_Conv[lock][IX_LOCK];
5653  assert (lock != NA_LOCK);
5654 
5656  }
5657  else
5658  {
5659  /* Fetch the rootclass object - no need to get last version for class */
5661  {
5662  /* Unable to lock the Rootclass. Undo the reserve of classname */
5663  (void) locator_delete_class_name (classname);
5664  return NULL;
5665  }
5666  }
5667 
5668  class_mop = ws_cache_with_oid (class_obj, &class_temp_oid, sm_Root_class_mop);
5669  if (class_mop != NULL)
5670  {
5671  ws_dirty (class_mop);
5672  ws_set_lock (class_mop, SCH_M_LOCK);
5673  }
5674 
5675  return class_mop;
5676 }
5677 
5678 /*
5679  * locator_create_heap_if_needed () - Make sure that a heap has been assigned
5680  *
5681  * return: classobject or NULL (in case of error)
5682  *
5683  * class_mop(in):
5684  * reuse_oid(in):
5685  *
5686  * Note: If a heap has not been assigned to store the instances of the
5687  * given class, one is assigned at this moment.
5688  */
5689 MOBJ
5690 locator_create_heap_if_needed (MOP class_mop, bool reuse_oid)
5691 {
5692  MOBJ class_obj; /* The class object */
5693  HFID *hfid; /* Heap where instance will be placed */
5694 
5695  /*
5696  * Get the class for the instance.
5697  * Assume that we are updating, inserting, deleting instances
5698  */
5699 
5700  class_obj = locator_fetch_class (class_mop, DB_FETCH_CLREAD_INSTWRITE);
5701  if (class_obj == NULL)
5702  {
5703  return NULL;
5704  }
5705 
5706  /*
5707  * Make sure that there is a heap for the instance. We cannot postpone
5708  * the creation of the heap since the class must be updated
5709  */
5710 
5711  hfid = sm_ch_heap (class_obj);
5712  if (HFID_IS_NULL (hfid))
5713  {
5714  OID *oid;
5715 
5716  /* Need to update the class, must fetch it again with write purpose */
5717  class_obj = locator_fetch_class (class_mop, DB_FETCH_WRITE);
5718  if (class_obj == NULL)
5719  {
5720  return NULL;
5721  }
5722 
5723  oid = ws_oid (class_mop);
5724  if (OID_ISTEMP (oid))
5725  {
5726  if (locator_flush_class (class_mop) != NO_ERROR)
5727  {
5728  return NULL;
5729  }
5730  oid = ws_oid (class_mop);
5731  }
5732 
5733  assert (!OID_ISNULL (sm_ch_rep_dir (class_obj)));
5734 
5735  if (heap_create (hfid, oid, reuse_oid) != NO_ERROR)
5736  {
5737  return NULL;
5738  }
5739 
5740  ws_dirty (class_mop);
5741  }
5742 
5743  assert (!OID_ISNULL (sm_ch_rep_dir (class_obj)));
5744 
5745  return class_obj;
5746 }
5747 
5748 /*
5749  * locator_has_heap () - Make sure that a heap has been assigned
5750  *
5751  * return: classobject or NULL (in case of error)
5752  *
5753  * class_mop(in):
5754  *
5755  * Note: If a heap has not been assigned to store the instances of the
5756  * given class, one is assigned at this moment.
5757  * If the class is a reusable OID class call
5758  * locator_create_heap_if_needed () instead of locator_has_heap ()
5759  */
5760 MOBJ
5762 {
5763  return locator_create_heap_if_needed (class_mop, false);
5764 }
5765 
5766 /*
5767  * locator_add_instance () - Insert an instance
5768  *
5769  * return: MOP
5770  *
5771  * instance(in): Instance object to add
5772  * class_mop(in): Mop of class which will hold the instance
5773  *
5774  * Note: Add a new object as an instance of the class associated with
5775  * the given class_mop. Neither the permanent OID for the new
5776  * instance nor a lock on the new instance are assigned at this
5777  * moment. The lock and OID are actually acquired when the
5778  * instance is flushed to the page buffer pool (server).
5779  * Only an IX lock is acquired on the class.
5780  */
5781 MOP
5783 {
5784  MOP mop; /* Mop of newly created instance */
5785  OID temp_oid; /* A temporarily OID for the newly created instance */
5786 
5787  /*
5788  * Make sure that there is a heap for the instance. We cannot postpone
5789  * the creation of the heap since the class must be updated
5790  */
5791 
5792  if (locator_create_heap_if_needed (class_mop, sm_is_reuse_oid_class (class_mop)) == NULL)
5793  {
5794  return NULL;
5795  }
5796 
5797  /*
5798  * Assign a temporarily OID. If the assigned OID is NULL, we need to flush to
5799  * recycle the temporarily OIDs.
5800  */
5801 
5802  OID_ASSIGN_TEMPOID (&temp_oid);
5803  if (OID_ISNULL (&temp_oid))
5804  {
5805  if (locator_all_flush () != NO_ERROR)
5806  {
5807  return NULL;
5808  }
5809 
5810  OID_INIT_TEMPID ();
5811  OID_ASSIGN_TEMPOID (&temp_oid);
5812  }
5813 
5814  /*
5815  * Insert the instance, set it dirty and cache the lock.. we need to cache
5816  * the lock since it was not acquired directly. Actually, it has not been
5817  * requested. It is set when the instance is flushed
5818  */
5819 
5820  mop = ws_cache_with_oid (instance, &temp_oid, class_mop);
5821  if (mop != NULL)
5822  {
5823  ws_dirty (mop);
5824  ws_set_lock (mop, X_LOCK);
5825  }
5826 
5827  return mop;
5828 }
5829 
5830 /*
5831  * locator_instance_decache () -
5832  *
5833  * return:
5834  *
5835  * mop(in):
5836  * ignore(in):
5837  *
5838  * Note:
5839  */
5840 static int
5841 locator_instance_decache (MOP mop, void *ignore)
5842 {
5843  ws_decache (mop);
5844  return WS_MAP_CONTINUE;
5845 }
5846 
5847 /*
5848  * locator_remove_class () - Remove a class
5849  *
5850  * return: NO_ERROR if all OK, ER status otherwise
5851  *
5852  * class_mop(in): Mop of class to delete
5853  *
5854  * Note: Delete a class. The deletion of the heap (i.e., all its
5855  * instances), and indices are deferred after commit time.
5856  */
5857 int
5859 {
5860  MOBJ class_obj; /* The class object */
5861  const char *classname; /* The classname */
5862  HFID *insts_hfid; /* Heap of instances of the class */
5863  int error_code = NO_ERROR;
5864 
5865  class_obj = locator_fetch_class (class_mop, DB_FETCH_WRITE);
5866  if (class_obj == NULL)
5867  {
5868  error_code = ER_FAILED;
5869  goto error;
5870  }
5871 
5872  /* Decache all the instances of the class */
5873  (void) ws_map_class (class_mop, locator_instance_decache, NULL);
5874 
5875  classname = sm_ch_name (class_obj);
5876 
5877  /* What should happen to the heap */
5878  insts_hfid = sm_ch_heap (class_obj);
5879  if (insts_hfid->vfid.fileid != NULL_FILEID)
5880  {
5881  error_code = heap_destroy_newly_created (insts_hfid, &class_mop->oid_info.oid);
5882  if (error_code != NO_ERROR)
5883  {
5884  goto error;
5885  }
5886  }
5887 
5888  /* Delete the class name */
5890  {
5891  ws_dirty (class_mop);
5892  ws_mark_deleted (class_mop);
5893  /*
5894  * Flush the deleted class so we do not have problems with the classname
5895  * to oid entry at a later point.
5896  */
5897  error_code = locator_flush_class (class_mop);
5898  }
5899 
5900 error:
5901  return error_code;
5902 }
5903 
5904 /*
5905  * locator_remove_instance () - Remove an instance
5906  *
5907  * return: nothing
5908  *
5909  * mop(in): Mop of instance to delete
5910  *
5911  * Note: Delete an instance. The instance is marked as deleted in the
5912  * workspace. The deletion of the instance on disk is deferred
5913  * until commit time.
5914  */
5915 void
5917 {
5918  ws_mark_deleted (mop);
5919 }
5920 
5921 /*
5922  * locator_update_class () - Prepare a class for update
5923  *
5924  * return: MOBJ
5925  *
5926  * mop(in): Mop of class that it is going to be updated
5927  *
5928  * Note: Prepare a class for update. The class is fetched for exclusive
5929  * mode and it is set dirty. Note that it is very important that
5930  * the class is set dirty before it is actually updated,
5931  * otherwise, the workspace may remain with a corrupted class if
5932  * a failure happens.
5933  *
5934  * This function should be called before the class is actually
5935  * updated.
5936  */
5937 MOBJ
5939 {
5940  MOBJ class_obj; /* The class object */
5941 
5942  class_obj = locator_fetch_class (mop, DB_FETCH_WRITE);
5943  if (class_obj != NULL)
5944  {
5945  ws_dirty (mop);
5946  }
5947 
5948  return class_obj;
5949 }
5950 
5951 /*
5952  * locator_prepare_rename_class () - Prepare a class for class rename
5953  *
5954  * return: The class or NULL
5955  *
5956  * class_mop(in): Mop of class that it is going to be renamed
5957  * old_classname(in): Oldname of class
5958  * new_classname(in): Newname of class
5959  *
5960  * Note: Prepare a class for a modification of its name from oldname to
5961  * newname. If the new_classname already exist, the value
5962  * LC_CLASSNAME_EXIST is returned. The value
5963  * LC_CLASSNAME_RESERVED_RENAME is returned when the operation
5964  * was successful. If the old_classname was previously removed,
5965  * the value LC_CLASSNAME_DELETED is returned. If the class is
5966  * not available or it does not exist, LC_CLASSNAME_ERROR is
5967  * returned.
5968  * The class is fetched in exclusive mode and it is set dirty for
5969  * its update. Note that it is very important that the class is
5970  * set dirty before it is actually updated, otherwise, the
5971  * workspace may remain with a corrupted class if a failure
5972  * happens.
5973  */
5974 MOBJ
5975 locator_prepare_rename_class (MOP class_mop, const char *old_classname, const char *new_classname)
5976 {
5977  MOBJ class_obj;
5978  MOP tmp_class_mop;
5979  LC_FIND_CLASSNAME renamed;
5980 
5981  /* Do we know about new name ? */
5982  if (new_classname == NULL)
5983  {
5984  return NULL;
5985  }
5986 
5987  tmp_class_mop = ws_find_class (new_classname);
5988  if (new_classname != NULL && tmp_class_mop != NULL && tmp_class_mop != class_mop
5989  && ws_get_lock (tmp_class_mop) != NULL_LOCK && !WS_IS_DELETED (tmp_class_mop))
5990  {
5991  /* The class already exist.. since it is cached */
5993  return NULL;
5994  }
5995 
5996  class_obj = locator_fetch_class (class_mop, DB_FETCH_WRITE);
5997  if (class_obj != NULL)
5998  {
5999  renamed = locator_rename_class_name (old_classname, new_classname, ws_oid (class_mop));
6000  if (renamed != LC_CLASSNAME_RESERVED_RENAME)
6001  {
6002  if (renamed == LC_CLASSNAME_EXIST)
6003  {
6005  }
6006  return NULL;
6007  }
6008 
6009  /* Invalidate old classname to MOP entry */
6010  ws_drop_classname (class_obj);
6011  ws_add_classname (class_obj, class_mop, new_classname);
6012  ws_dirty (class_mop);
6013  }
6014 
6015  return class_obj;
6016 }
6017 
6018 /*
6019  * locator_update_instance () - Prepare an instance for update
6020  *
6021  * return: MOBJ
6022  *
6023  * mop(in): Mop of object that it is going to be updated
6024  *
6025  * Note:Prepare an instance for update. The instance is fetched for
6026  * exclusive mode and it is set dirty. Note that it is very
6027  * important the the instance is set dirty before it is actually
6028  * updated, otherwise, the workspace may remain with a corrupted
6029  * instance if a failure happens.
6030  *
6031  * This function should be called before the instance is actually
6032  * updated.
6033  */
6034 MOBJ
6036 {
6037  MOBJ object; /* The instance object */
6038 
6040  if (object != NULL)
6041  {
6042  ws_dirty (mop);
6043  }
6044 
6045  return object;
6046 }
6047 
6048 #if defined (ENABLE_UNUSED_FUNCTION)
6049 /*
6050  * locator_update_tree_classes () - Prepare a tree of classes for update
6051  *
6052  * return: NO_ERROR if all OK, ER status otherwise
6053  *
6054  * classes_mop_set(in): An array of Mops
6055  * num_classes(in): Number of classes
6056  *
6057  * Note: Prepare a tree of classes (usually a class and its subclasses)
6058  * for updates. This statement must be executed during schema
6059  * changes that will affect a tree of classes.
6060  * This function should be called before the classes are actually
6061  * updated.
6062  */
6063 int
6064 locator_update_tree_classes (MOP * classes_mop_set, int num_classes)
6065 {
6066  return locator_lock_set (num_classes, classes_mop_set, X_LOCK, SCH_M_LOCK, true);
6067 }
6068 #endif /* ENABLE_UNUSED_FUNCTION */
6069 
6070 /*
6071  * locator_assign_permanent_oid () - Assign a permanent_oid
6072  *
6073  * return: OID *
6074  *
6075  * mop(in): Mop of object with temporal oid
6076  *
6077  * Note: Assign a permanent oid to the object associated with the given mop.
6078  * This function is needed during flushing of new objects with circular
6079  * dependencies (For example, an object points to itself). Otherwise, OIDs for
6080  * new objects are assigned automatically when the objects are placed
6081  * on the heap.
6082  */
6083 OID *
6085 {
6086  MOBJ object; /* The object */
6087  int expected_length; /* Expected length of disk object */
6088  OID perm_oid; /* Permanent OID of object. Assigned as a side effect */
6089  MOP class_mop; /* The class mop */
6090  MOBJ class_obj; /* The class object */
6091  const char *name;
6092  HFID *hfid; /* Heap where the object is going to be stored */
6093 
6094  /* Find the expected length of the object */
6095 
6096  class_mop = ws_class_mop (mop);
6097  if (class_mop == NULL || (class_obj = locator_fetch_class (class_mop, DB_FETCH_CLREAD_INSTWRITE)) == NULL)
6098  {
6099  /* Could not assign a permanent OID */
6100  return NULL;
6101  }
6102 
6103  /* Get the object */
6104  if (ws_find (mop, &object) == WS_FIND_MOP_DELETED)
6105  {
6106  OID *oid;
6107 
6108  oid = ws_oid (mop);
6110  return NULL;
6111  }
6112 
6113  /* Get an approximation for the expected size */
6114  if (object != NULL && class_obj != NULL)
6115  {
6116  expected_length = tf_object_size (class_obj, object);
6117  if (expected_length < (int) sizeof (OID))
6118  {
6119  expected_length = (int) sizeof (OID);
6120  }
6121  }
6122  else
6123  {
6124  expected_length = (int) sizeof (OID);
6125  }
6126 
6127  /* Find the heap where the object will be stored */
6128 
6129  name = NULL;
6130  if (locator_is_root (class_mop))
6131  {
6132  /* Object is a class */
6133  hfid = sm_Root_class_hfid;
6134  if (object != NULL)
6135  {
6136  name = sm_ch_name (object);
6137  }
6138  }
6139  else
6140  {
6141  hfid = sm_ch_heap (class_obj);
6142  }
6143 
6144  /* Assign an address */
6145 
6146  if (locator_assign_oid (hfid, &perm_oid, expected_length, ws_oid (class_mop), name) != NO_ERROR)
6147  {
6149  {
6150  (void) tran_abort_only_client (false);
6151  }
6152 
6153  return NULL;
6154  }
6155 
6156  /* Reset the OID of the mop */
6157  ws_update_oid (mop, &perm_oid);
6158 
6159  return ws_oid (mop);
6160 }
6161 
6162 /*
6163  * locator_synch_isolation_incons () - Synchronize isolation inconsistencies
6164  *
6165  * return: nothing
6166  *
6167  * Note: Find any isolation inconsistencies due to releasing locks in
6168  * the middle of the transaction.
6169  */
6170 void
6172 {
6173  LC_COPYAREA *fetch_area; /* Area where objects are received */
6174  int more_synch;
6175 
6177  {
6178  return;
6179  }
6180 
6181  do
6182  {
6183  more_synch = locator_notify_isolation_incons (&fetch_area);
6184  if (fetch_area == NULL)
6185  {
6186  break;
6187  }
6188  (void) locator_cache (fetch_area, NULL, NULL, NULL, NULL);
6189  locator_free_copy_area (fetch_area);
6190  }
6191  while (more_synch);
6192 
6193 }
6194 
6195 /*
6196  * locator_cache_lock_lockhint_classes :
6197  *
6198  * return:
6199  *
6200  * lockhint(in):
6201  *
6202  * NOTE : Cache the lock for the desired classes.
6203  * We need to do this since we don't know if the classes were received in
6204  * the fetch areas. That is, they may have not been sent since the cached
6205  * class is upto date.
6206  *
6207  */
6208 static void
6210 {
6211  int i;
6212  MOP class_mop = NULL; /* The mop of a class */
6213  MOBJ class_obj; /* The class object of above mop */
6214  LOCK lock; /* The lock granted to above class */
6215  WS_FIND_MOP_STATUS status;
6216 
6217  for (i = 0; i < lockhint->num_classes; i++)
6218  {
6219  if (!OID_ISNULL (&lockhint->classes[i].oid))
6220  {
6221  class_mop = ws_mop (&lockhint->classes[i].oid, sm_Root_class_mop);
6222  if (class_mop != NULL)
6223  {
6224  status = (WS_FIND_MOP_STATUS) ws_find (class_mop, &class_obj);
6225  if (status != WS_FIND_MOP_DELETED && class_obj != NULL)
6226  {
6227  lock = ws_get_lock (class_mop);
6228  assert (lockhint->classes[i].lock >= NULL_LOCK && lock >= NULL_LOCK);
6229  lock = lock_Conv[lockhint->classes[i].lock][lock];
6230  assert (lock != NA_LOCK);
6231 
6232  ws_set_lock (class_mop, lock);
6233  }
6234  }
6235  }
6236  }
6237 }
6238 
6239 /*
6240  * locator_lockhint_classes () - The given classes should be prelocked and prefetched
6241  * since they are likely to be needed
6242  *
6243  * return: LC_FIND_CLASSNAME
6244  * (either of LC_CLASSNAME_EXIST,
6245  * LC_CLASSNAME_DELETED,
6246  * LC_CLASSNAME_ERROR)
6247  *
6248  * num_classes(in): Number of needed classes
6249  * many_classnames(in): Name of the classes
6250  * many_locks(in): The desired lock for each class
6251  * need_subclasses(in): Wheater or not the subclasses are needed.
6252  * flags(in): array of flags associated with class names
6253  * quit_on_errors(in): Wheater to continue finding the classes in case of an
6254  * error, such as a class does not exist or locks on some
6255  * of the classes may not be granted.
6256  * lock_rr_tran(in): lock repeatable read transaction if not NULL_LOCK.
6257  *
6258  */
6260 locator_lockhint_classes (int num_classes, const char **many_classnames, LOCK * many_locks, int *need_subclasses,
6261  LC_PREFETCH_FLAGS * flags, int quit_on_errors, LOCK lock_rr_tran)
6262 {
6263  MOP class_mop = NULL; /* The mop of a class */
6264  MOBJ class_obj = NULL; /* The class object of above mop */
6265  LOCK current_lock; /* The lock granted to above class */
6266  LC_LOCKHINT *lockhint = NULL; /* Description of hinted classes to lock and fetch */
6267  LC_COPYAREA *fetch_area; /* Area where objects are received */
6268  LC_FIND_CLASSNAME all_found; /* Result of search */
6269  bool need_call_server; /* Do we need to invoke the server to find the classes ? */
6270  bool need_flush;
6271  int error_code = NO_ERROR;
6272  int i;
6273  OID *guessmany_class_oids = NULL;
6274  int *guessmany_class_chns = NULL;
6275  LOCK conv_lock;
6276 
6277  all_found = LC_CLASSNAME_EXIST;
6278  need_call_server = need_flush = false;
6279 
6280  /*
6281  * Check if we need to call the server
6282  */
6283 
6284  for (i = 0; i < num_classes && (need_call_server == false || need_flush == false); i++)
6285  {
6286  if (many_classnames[i])
6287  {
6288  /*
6289  * If we go to the server, let us flush any new class (temp OID or
6290  * small cache coherance number) or a class that has been deleted
6291  */
6292  class_mop = ws_find_class (many_classnames[i]);
6293  if (class_mop == NULL)
6294  {
6295  need_call_server = true;
6296  continue;
6297  }
6298 
6299  if (WS_ISDIRTY (class_mop)
6300  && (OID_ISTEMP (ws_oid (class_mop)) || ws_find (class_mop, &class_obj) == WS_FIND_MOP_DELETED
6301  || (class_obj != NULL && WS_CHN (class_obj) <= 1)))
6302  {
6303  need_flush = true;
6304  }
6305 
6306  if (need_call_server == true)
6307  {
6308  continue;
6309  }
6310 
6311  /*
6312  * If the subclasses or count optimization are needed, go to the
6313  * server for now.
6314  */
6315  if (need_subclasses[i] > 0 || (flags[i] & LC_PREF_FLAG_COUNT_OPTIM))
6316  {
6317  need_call_server = true;
6318  continue;
6319  }
6320 
6321  /*
6322  * Check if the classname to OID entry is cached. Trust the cache only
6323  * if there is a lock on the class
6324  */
6325  current_lock = ws_get_lock (class_mop);
6326  assert (many_locks[i] >= NULL_LOCK && current_lock >= NULL_LOCK);
6327  conv_lock = lock_Conv[many_locks[i]][current_lock];
6328  assert (conv_lock != NA_LOCK);
6329 
6330  if (current_lock == NULL_LOCK || current_lock != conv_lock)
6331  {
6332  need_call_server = true;
6333  continue;
6334  }
6335  }
6336  }
6337 
6338  /*
6339  * Do we Need to find out the classnames to oids in the server?
6340  */
6341 
6342  if (!need_call_server)
6343  {
6344  goto error;
6345  }
6346 
6347  guessmany_class_oids = (OID *) malloc (sizeof (*guessmany_class_oids) * num_classes);
6348  if (guessmany_class_oids == NULL)
6349  {
6351  sizeof (*guessmany_class_oids) * num_classes);
6352  return LC_CLASSNAME_ERROR;
6353  }
6354 
6355  guessmany_class_chns = (int *) malloc (sizeof (*guessmany_class_chns) * num_classes);
6356  if (guessmany_class_chns == NULL)
6357  {
6358  if (guessmany_class_oids != NULL)
6359  {
6360  free_and_init (guessmany_class_oids);
6361  }
6362 
6364  sizeof (*guessmany_class_chns) * num_classes);
6365  return LC_CLASSNAME_ERROR;
6366  }
6367 
6368  for (i = 0; i < num_classes; i++)
6369  {
6370  if (many_classnames[i] && (class_mop = ws_find_class (many_classnames[i])) != NULL)
6371  {
6372  /*
6373  * Flush the class when the class has never been flushed and/or
6374  * the class has been deleted.
6375  */
6376  if (need_flush == true)
6377  {
6378  /*
6379  * May be, we should flush in a set (ala mflush)
6380  */
6381  if (WS_ISDIRTY (class_mop)
6382  && (OID_ISTEMP (ws_oid (class_mop)) || ws_find (class_mop, &class_obj) == WS_FIND_MOP_DELETED
6383  || (class_obj != NULL && WS_CHN (class_obj) <= 1)))
6384  {
6385  (void) locator_flush_class (class_mop);
6386  }
6387  }
6388 
6389  if (guessmany_class_oids != NULL)
6390  {
6391  if (ws_find (class_mop, &class_obj) != WS_FIND_MOP_DELETED && class_obj != NULL)
6392  {
6393  /*
6394  * The class is cached
6395  */
6396  COPY_OID (&guessmany_class_oids[i], ws_oid (class_mop));
6397  guessmany_class_chns[i] = ws_chn (class_obj);
6398  }
6399  else
6400  {
6401  OID_SET_NULL (&guessmany_class_oids[i]);
6402  guessmany_class_chns[i] = NULL_CHN;
6403  }
6404  }
6405  }
6406  else
6407  {
6408  if (guessmany_class_oids != NULL)
6409  {
6410  OID_SET_NULL (&guessmany_class_oids[i]);
6411  guessmany_class_chns[i] = NULL_CHN;
6412  }
6413  }
6414  }
6415 
6416  all_found =
6417  locator_find_lockhint_class_oids (num_classes, many_classnames, many_locks, need_subclasses, flags,
6418  guessmany_class_oids, guessmany_class_chns, quit_on_errors, lock_rr_tran,
6419  &lockhint, &fetch_area);
6420 
6421  if (guessmany_class_oids != NULL)
6422  {
6423  free_and_init (guessmany_class_oids);
6424  }
6425 
6426  if (guessmany_class_chns != NULL)
6427  {
6428  free_and_init (guessmany_class_chns);
6429  }
6430 
6431  if (lockhint != NULL && lockhint->num_classes > lockhint->num_classes_processed)
6432  {
6433  /*
6434  * Rest the cache coherence numbers to avoid receiving classes with the
6435  * right state (chn) in the workspace.
6436  * We could have started with the number of classes processed, however,
6437  * we start from zero to set to NULL_OID any class that are deleted in
6438  * the workspace.
6439  */
6440  for (i = 0; i < lockhint->num_classes; i++)
6441  {
6442  if (!OID_ISNULL (&lockhint->classes[i].oid)
6443  && ((class_mop = ws_mop (&lockhint->classes[i].oid, sm_Root_class_mop)) == NULL
6444  || ws_find (class_mop, &class_obj) == WS_FIND_MOP_DELETED))
6445  {
6446  OID_SET_NULL (&lockhint->classes[i].oid);
6447  }
6448  else
6449  {
6450  lockhint->classes[i].chn = ws_chn (class_obj);
6451  }
6452  }
6453  }
6454 
6455  /*
6456  * If we received any classes, cache them
6457  */
6458 
6459  if (fetch_area != NULL)
6460  {
6461  /* Cache the classes that were brought from the server */
6462  if (locator_cache (fetch_area, sm_Root_class_mop, NULL, NULL, NULL) != NO_ERROR)
6463  {
6464  all_found = LC_CLASSNAME_ERROR;
6465  }
6466  locator_free_copy_area (fetch_area);
6467  }
6468 
6469  if (all_found == LC_CLASSNAME_ERROR && er_errid () == ER_LK_UNILATERALLY_ABORTED)
6470  {
6471  (void) tran_abort_only_client (false);
6472  quit_on_errors = true;
6473  }
6474 
6475  /*
6476  * Now get the rest of the objects and classes
6477  */
6478 
6479  if (lockhint != NULL && (all_found == LC_CLASSNAME_EXIST || quit_on_errors == false))
6480  {
6481  int i, idx = 0;
6482  LC_COPYAREA *fetch_copyarea[MAX_FETCH_SIZE];
6483  LC_COPYAREA **fetch_ptr = fetch_copyarea;
6484 
6485  if (lockhint->num_classes > MAX_FETCH_SIZE)
6486  {
6487  fetch_ptr = (LC_COPYAREA **) malloc (sizeof (LC_COPYAREA *) * lockhint->num_classes);
6488 
6489  if (fetch_ptr == NULL)
6490  {
6491  return LC_CLASSNAME_ERROR;
6492  }
6493  }
6494 
6495  error_code = NO_ERROR;
6496  while (error_code == NO_ERROR && lockhint->num_classes > lockhint->num_classes_processed)
6497  {
6498  fetch_ptr[idx] = NULL;
6499  error_code = locator_fetch_lockhint_classes (lockhint, &fetch_ptr[idx]);
6500  if (error_code != NO_ERROR)
6501  {
6502  if (fetch_ptr[idx] != NULL)
6503  {
6504  locator_free_copy_area (fetch_ptr[idx]);
6505  fetch_ptr[idx] = NULL;
6506  }
6507  }
6508 
6509  idx++;
6510  }
6511 
6512  for (i = 0; i < idx; i++)
6513  {
6514  if (fetch_ptr[i] != NULL)
6515  {
6516  locator_cache (fetch_ptr[i], sm_Root_class_mop, NULL, NULL, NULL);
6517  locator_free_copy_area (fetch_ptr[i]);
6518  }
6519  }
6520 
6521  if (fetch_ptr != fetch_copyarea)
6522  {
6523  free_and_init (fetch_ptr);
6524  }
6525  }
6526 
6527  /*
6528  * Cache the lock of the hinted classes
6529  */
6530 
6531  if (lockhint != NULL && (all_found == LC_CLASSNAME_EXIST || quit_on_errors == false))
6532  {
6534  }
6535 
6536  if (lockhint != NULL)
6537  {
6538  locator_free_lockhint (lockhint);
6539  }
6540 
6541 error:
6542  return all_found;
6543 }
6544 
6545 
6546 /*
6547  * Client oidset processing
6548  */
6549 
6550 /*
6551  * Most of the LC_OIDSET code is in locator.c as it in theory could be used
6552  * by either the client or server and the packing/unpacking code in fact
6553  * has to be shared.
6554  *
6555  * In practice though, the construction of an LC_OIDSET from scratch is
6556  * only done by the client who will then send it to the server for processing.
6557  * When the oidset comes back, we then have to take care to update the
6558  * workspace MOPs for the changes in OIDs. This is an operation that
6559  * the client side locator should do as it requires access to workspace
6560  * internals.
6561  *
6562  * The usual pattern for the client is this:
6563  *
6564  * locator_make_oid_set begin a structure
6565  * locator_add_oidset_object populate it with entries
6566  * ...
6567  * locator_assign_oidset assign the OIDs and update the workspace
6568  *
6569  */
6570 
6571 static int
6572 locator_check_object_and_get_class (MOP obj_mop, MOP * out_class_mop)
6573 {
6574  int error_code = NO_ERROR;
6575  MOP class_mop;
6576 
6577  if (obj_mop == NULL || obj_mop->object == NULL)
6578  {
6580  error_code = ER_GENERIC_ERROR;
6581  goto error;
6582  }
6583 
6584  class_mop = ws_class_mop (obj_mop);
6585  if (class_mop == NULL || class_mop->object == NULL)
6586  {
6588  error_code = ER_GENERIC_ERROR;
6589  goto error;
6590  }
6591 
6592  if (!OID_ISTEMP (ws_oid (obj_mop)))
6593  {
6595  error_code = ER_LC_UNEXPECTED_PERM_OID;
6596  goto error;
6597  }
6598 
6599  /*
6600  * Ensure that the class has been flushed at this point.
6601  * HFID can't be NULL at this point since we've got an instance for
6602  * this class. Could use locator_has_heap to make sure.
6603  */
6604 
6605  if (OID_ISTEMP (ws_oid (class_mop)))
6606  {
6607  error_code = locator_flush_class (class_mop);
6608  if (error_code != NO_ERROR)
6609  {
6610  goto error;
6611  }
6612  }
6613 
6614  *out_class_mop = class_mop;
6615 
6616 error:
6617  return error_code;
6618 }
6619 
6620 /*
6621  * locator_add_oidset_object () - Add object to oidset
6622  *
6623  * return: oidmap structure for this object
6624  *
6625  * oidset(in): oidset to extend
6626  * obj_mop(in): object to add
6627  */
6628 LC_OIDMAP *
6630 {
6631  MOP class_mop;
6632  LC_OIDMAP *oid_map_p;
6633 
6634  if (locator_check_object_and_get_class (obj_mop, &class_mop) != NO_ERROR)
6635  {
6636  return NULL;
6637  }
6638 
6639  oid_map_p =
6640  locator_add_oid_set (NULL, oidset, sm_ch_heap ((MOBJ) (class_mop->object)), WS_OID (class_mop), WS_OID (obj_mop));
6641  if (oid_map_p == NULL)
6642  {
6643  return NULL;
6644  }
6645 
6646  /* remember the object handle so it can be updated later */
6647  if (oid_map_p->mop == NULL)
6648  {
6649  oid_map_p->mop = (void *) obj_mop;
6650 
6651  /*
6652  * Since this is the first time we've been here, compute the estimated
6653  * storage size. This could be rather expensive, may want to just
6654  * keep an approximate size guess in the class rather than walking
6655  * over the object. If this turns out to be an expensive operation
6656  * (which should be unlikely relative to the cost of a server call), we can
6657  * just put -1 here and the heap manager will use some internal statistics
6658  * to make a good guess.
6659  */
6660  oid_map_p->est_size = tf_object_size ((MOBJ) (ws_class_mop (obj_mop)->object), (MOBJ) (obj_mop->object));
6661  }
6662 
6663  return oid_map_p;
6664 }
6665 
6666 /*
6667  * locator_assign_oidset () -
6668  *
6669  * return: NO_ERROR if all OK, ER status otherwise
6670  *
6671  * oidset(in): oidset to process
6672  * callback(in): Callback function to do extra work
6673  *
6674  * Note:This is the primary client side function for processing an
6675  * LC_OIDSET and updating the workspace.
6676  * The oidset is expected to have been populated by locator_add_oidset_object
6677  * so that the o->mop fields will point directly to the workspace
6678  * handles for fast updating.
6679  *
6680  * Callback function if passed will be called for each LC_OIDMAP entry
6681  * so the caller can do something extra with the client_data state for
6682  * each object.
6683  * The callback function cannot do anything that would result in an
6684  * error so be careful.
6685  */
6686 int
6688 {
6689  int error_code = NO_ERROR;
6690  LC_CLASS_OIDSET *class_oidset;
6691  LC_OIDMAP *oid;
6692  int status;
6693 
6694  if (oidset != NULL && oidset->total_oids > 0)
6695  {
6696  /*
6697  * Note:, it is currently defined that if the server returns a
6698  * failure here that it will have "rolled back" any partial results
6699  * it may have obtained, this means that we don't have to worry about
6700  * updating the workspace here for the permanent OID's that might
6701  * have been assigned before an error was encountered.
6702  */
6703  status = locator_assign_oid_batch (oidset);
6704  if (status != NO_ERROR)
6705  {
6706  /* make sure we faithfully return whatever error the server sent back */
6707  assert (er_errid () != NO_ERROR);
6708  error_code = er_errid ();
6709  }
6710  else
6711  {
6712  /* Map through the oidset and update the workspace */
6713  for (class_oidset = oidset->classes; class_oidset != NULL; class_oidset = class_oidset->next)
6714  {
6715  for (oid = class_oidset->oids; oid != NULL; oid = oid->next)
6716  {
6717  if (oid->mop != NULL)
6718  {
6719  ws_update_oid ((MOP) oid->mop, &oid->oid);
6720  }
6721 
6722  /* let the callback function do further processing if necessary */
6723  if (callback != NULL)
6724  {
6725  (*callback) (oid);
6726  }
6727  }
6728  }
6729  }
6730  }
6731 
6732  return error_code;
6733 }
6734 
6735 /*
6736  * locator_add_to_oidset_when_temp_oid () -
6737  *
6738  * return: WS_MAP_ status code
6739  *
6740  * mop(in): object to examine
6741  * data(in): pointer to the LC_OIDSET we're populating
6742  *
6743  * Note:This is a mapping function passed to ws_map_dirty by
6744  * locator_assign_all_permanent_oids. Here we check to see if the object
6745  * will eventually be flushed and if so, we call tf_find_temporary_oids
6746  * to walk over the object and add all the temporary OIDs that object
6747  * contains to the LC_OIDSET.
6748  * After walking over the object, we check to see if we've exceeded
6749  * OID_BATCH_SIZE and if so, we assign the OIDs currently in the
6750  * oidset, clear the oidset, and continue with the next batch.
6751  */
6752 static int
6754 {
6755  LC_OIDSET *oidset = (LC_OIDSET *) data;
6756  OID *oid;
6757  int map_status;
6758  MOBJ object;
6759  MOP class_mop = NULL;
6760 
6761  map_status = WS_MAP_CONTINUE;
6762  if (WS_ISVID (mop))
6763  {
6764  return map_status;
6765  }
6766  class_mop = ws_class_mop (mop);
6767  if (class_mop != NULL)
6768  {
6769  SM_CLASS *class_ = (SM_CLASS *) class_mop->object;
6770  if (class_->partition != NULL && class_->users != NULL)
6771  {
6772  /* do not assign permanent OIDs to objects inserted into partitioned classes yet because we don't know in
6773  * which partition they will end up */
6774  return WS_MAP_CONTINUE;
6775  }
6776  }
6777  else
6778  {
6779  /* can this actually happen? */
6780  assert (false);
6781  }
6782 
6783  oid = ws_oid (mop);
6784 
6785  if (OID_ISTEMP (oid) && ws_find (mop, &object) != WS_FIND_MOP_DELETED)
6786  {
6787  if (locator_add_oidset_object (oidset, mop) == NULL)
6788  {
6789  return WS_MAP_FAIL;
6790  }
6791 
6792  /*
6793  * If we've gone over our threshold, flush the ones we have so far,
6794  * and clear out the oidset for more. We may want to make this
6795  * part of locator_add_oidset_object rather than doing it out here.
6796  */
6797  if (oidset->total_oids > OID_BATCH_SIZE)
6798  {
6799  if (locator_assign_oidset (oidset, NULL) != NO_ERROR)
6800  {
6801  return WS_MAP_FAIL;
6802  }
6803 
6804  locator_clear_oid_set (NULL, oidset);
6805  }
6806  }
6807 
6808  return map_status;
6809 }
6810 
6811 /*
6812  * locator_assign_all_permanent_oids () -
6813  *
6814  * return: NO_ERROR if all OK, ER status otherwise
6815  *
6816  * Note:This function will turn all of the temporary OIDs in the workspace
6817  * into permanent OIDs. This will be done by issuing one or more
6818  * calls to locator_assign_oidset using an LC_OIDSET that has been populated
6819  * by walking over every dirty object in the workspace.
6820  *
6821  * This is intended to be called during transaction commit processing
6822  * before we start flushing objects. It will ensure that all object
6823  * references will be promoted to permanent OIDs which will reduce
6824  * the number of server calls we have to make while the objects
6825  * are being flushed.
6826  *
6827  * Note: It is not GUARANTEED that all temporary OIDs will have been
6828  * promoted after this function is complete. We will try to promote
6829  * all of them, and in practice, that will be the usual case. The caller
6830  * should not however rely on this behavior and later processing must
6831  * be prepared to encounter temporary OIDs and handle them in the usual
6832  * way. This function is intended as a potential optimization only,
6833  * it cannot be relied upon to assign permanent OIDs.
6834  */
6835 int
6837 {
6838  int error_code = NO_ERROR, map_status;
6839  LC_OIDSET *oidset;
6840 
6841  oidset = locator_make_oid_set ();
6842  if (oidset == NULL)
6843  {
6844  return ER_FAILED;
6845  }
6846 
6847  map_status = ws_map_dirty (locator_add_to_oidset_when_temp_oid, oidset);
6848  if (map_status == WS_MAP_FAIL)
6849  {
6850  error_code = ER_FAILED;
6851  goto error;
6852  }
6853 
6854  error_code = locator_assign_oidset (oidset, NULL);
6855 
6856 error:
6857  locator_free_oid_set (NULL, oidset);
6858  return error_code;
6859 }
6860 
6861 /*
6862  * locator_flush_replication_info () -
6863  *
6864  * return: NO_ERROR if all OK, ER status otherwise
6865  *
6866  * repl_info(in):
6867  */
6868 int
6870 {
6871  return repl_set_info (repl_info);
6872 }
6873 
6874 /*
6875  * locator_get_append_lsa () -
6876  *
6877  * return:NO_ERROR if all OK, ER status otherwise
6878  *
6879  * lsa(in):
6880  */
6881 int
6883 {
6884  return repl_log_get_append_lsa (lsa);
6885 }
6886 
6887 /*
6888  * locator_can_skip_fetch_from_server () - Check whether object fetch from
6889  * server can be skipped based on
6890  * locks and snapshot version.
6891  *
6892  * return : True if server fetch can be skipped. False otherwise.
6893  * mop (in) : Mop that
6894  * lock (in/out) : Required lock. Output is results of lock convention
6895  * between input lock and current lock.
6896  * fetch_version_type(in): fetch version type
6897  */
6898 static bool
6900 {
6901  MOP class_mop = ws_class_mop (mop);
6902  LOCK crt_lock = ws_get_lock (mop);
6903  OID *oid = ws_oid (mop);
6904  MOBJ object = NULL;
6905 
6906  assert (*lock >= NULL_LOCK);
6907  assert (crt_lock >= NULL_LOCK);
6908 
6909  /* Should we check the result of ws_find here? */
6910  (void) ws_find (mop, &object);
6911  if (object == NULL)
6912  {
6913  /* Object is not fetched or was deleted */
6914  return false;
6915  }
6916 
6917  /* Check lock */
6918  *lock = lock_Conv[*lock][crt_lock];
6919  if (crt_lock != NULL_LOCK && (*lock == crt_lock || OID_ISTEMP (oid)))
6920  {
6921  /* Object was already locked and lock doesn't need to be promoted */
6922  return true;
6923  }
6924 
6925  if (class_mop != NULL && class_mop != sm_Root_class_mop && *lock == NULL_LOCK)
6926  {
6927  /* Go to server only if required lock is at least shared lock. */
6929  }
6930 
6931  /* We are here because we need to upgrade lock on object. */
6932  return false;
6933 }
bool sm_has_indexes(MOBJ classobj)
enum ws_map_status WS_MAP_STATUS
Definition: work_space.h:413
LC_FETCH_VERSION_TYPE
Definition: locator.h:178
#define ROOTCLASS_NAME
Definition: oid.h:32
int locator_does_exist(OID *oidp, int chn, LOCK lock, OID *class_oid, int class_chn, int need_fetching, int prefetch, LC_COPYAREA **fetch_copyarea, LC_FETCH_VERSION_TYPE fetch_version_type)
#define ER_LK_UNILATERALLY_ABORTED
Definition: error_code.h:130
#define ER_HEAP_UNKNOWN_CLASS_OF_INSTANCE
Definition: error_code.h:103
static void locator_mflush_set_dirty(MOP mop, MOBJ ignore_object, void *ignore_argument)
Definition: locator_cl.c:3977
WS_REPL_OBJ * ws_get_repl_obj_from_list(void)
Definition: work_space.c:5335
OID * oid_Root_class_oid
Definition: oid.c:73
static int locator_mflush_initialize(LOCATOR_MFLUSH_CACHE *mflush, MOP class_mop, MOBJ clazz, HFID *hfid, bool decache, bool isone_mflush)
Definition: locator_cl.c:3799
LC_LOCKSET_CLASSOF * classes
Definition: locator.h:303
void ws_clean(MOP op)
Definition: work_space.c:1681
#define WS_IS_DELETED(mop)
Definition: work_space.h:284
#define NO_ERROR
Definition: error_code.h:46
#define WS_MOP_SET_PRUNE_LEVEL(mop, value)
Definition: work_space.h:361
int repl_set_info(REPL_INFO *repl_info)
int area_size
#define AU_DISABLE(save)
Definition: authenticate.h:106
int locator_get_append_lsa(struct log_lsa *lsa)
Definition: locator_cl.c:6882
static int locator_mflush_force(LOCATOR_MFLUSH_CACHE *mflush)
Definition: locator_cl.c:4067
void er_stack_push(void)
LOCATOR_MFLUSH_TEMP_OID * mop_toids
Definition: locator_cl.c:74
static int locator_internal_flush_instance(MOP inst_mop, bool decache)
Definition: locator_cl.c:5135
LC_FIND_CLASSNAME locator_find_lockhint_class_oids(int num_classes, const char **many_classnames, LOCK *many_locks, int *many_need_subclasses, LC_PREFETCH_FLAGS *many_flags, OID *guessed_class_oids, int *guessed_class_chns, int quit_on_errors, LOCK lock_rr_tran, LC_LOCKHINT **lockhint, LC_COPYAREA **fetch_copyarea)
#define WS_SET_FOUND_DELETED(mop)
Definition: locator_cl.c:56
static int locator_lock_class_of_instance(MOP inst_mop, MOP *class_mop, LOCK lock)
Definition: locator_cl.c:1681
#define ASSERT_ERROR()
static int locator_class_to_disk(LOCATOR_MFLUSH_CACHE *mflush, MOBJ object, bool *has_index, int *round_length_p, WS_MAP_STATUS *map_status)
Definition: locator_cl.c:4271
MOP ws_mop(const OID *oid, MOP class_mop)
Definition: work_space.c:614
int sm_decache_mop(MOP mop, void *info)
int locator_notify_isolation_incons(LC_COPYAREA **synch_copyarea)
DB_OBJECT * db_real_instance(DB_OBJECT *obj)
Definition: db_virt.c:247
char * MOBJ
Definition: work_space.h:174
#define LC_PRIOR_ONEOBJ_PTR_IN_COPYAREA(oneobj_ptr)
Definition: locator.h:49
void ws_set_class(MOP inst, MOP class_mop)
Definition: work_space.c:1997
OID class_oid
Definition: work_space.h:83
RECDES * recdes
Definition: work_space.h:88
int sm_mark_system_class(MOP classop, int on_or_off)
MOBJ locator_fetch_set(int num_mops, MOP *mop_set, DB_FETCH_MODE inst_purpose, DB_FETCH_MODE class_purpose, int quit_on_errors)
Definition: locator_cl.c:2464
#define MAX_FETCH_SIZE
Definition: locator_cl.c:57
void locator_free_copy_area(LC_COPYAREA *copyarea)
Definition: locator.c:534
int locator_assign_oid_batch(LC_OIDSET *oidset)
static volatile sig_atomic_t lc_Is_siginterrupt
Definition: locator_cl.c:114
void ws_dirty(MOP op)
Definition: work_space.c:1622
MOBJ locator_create_heap_if_needed(MOP class_mop, bool reuse_oid)
Definition: locator_cl.c:5690
#define LC_DOESNOT_EXIST
int locator_fetch_lockset(LC_LOCKSET *lockset, LC_COPYAREA **fetch_copyarea)
void ws_mark_deleted(MOP mop)
Definition: work_space.c:3081
int ws_map_class_dirty(MOP class_op, MAPFUNC function, void *args)
Definition: work_space.c:2018
#define OID_ASSIGN_TEMPOID(oidp)
Definition: oid.h:49
#define ER_FAILED
Definition: error_code.h:47
#define LC_START_ONEOBJ_PTR_IN_COPYAREA(manyobjs_ptr)
Definition: locator.h:44
char * packed_pkey_value
Definition: work_space.h:84
static int locator_cache(LC_COPYAREA *copy_area, MOP hint_class_mop, MOBJ hint_class, void(*fun)(MOP mop, MOBJ object, void *args), void *args)
Definition: locator_cl.c:3707
void locator_manyobj_flag_set(LC_COPYAREA_MANYOBJS *copyarea, enum MULTI_UPDATE_FLAG muf)
Definition: locator.c:2610
#define LC_ERROR
MOBJ tf_disk_to_mem(MOBJ classobj, RECDES *record, int *convertp)
int locator_repl_force(LC_COPYAREA *copy_area, LC_COPYAREA **reply_copy_area)
char * mem
Definition: locator.h:247
const void * mht_put(MHT_TABLE *ht, const void *key, void *data)
Definition: memory_hash.c:1778
#define LC_FETCH_IS_DIRTY_VERSION_NEEDED(fetch_type)
Definition: locator.h:189
SM_PARTITION * partition
Definition: class_object.h:760
#define ASSERT_ERROR_AND_SET(error_code)
int num_classes_processed
Definition: locator.h:325
static LC_FIND_CLASSNAME locator_find_class_by_oid(MOP *class_mop, const char *classname, OID *class_oid, LOCK lock)
Definition: locator_cl.c:2997
int ws_chn(MOBJ obj)
Definition: work_space.c:2922
int est_size
Definition: locator.h:353
enum ws_find_mop_status WS_FIND_MOP_STATUS
Definition: work_space.h:424
int ws_Error_ignore_count
Definition: work_space.c:161
#define LC_FIND_ONEOBJ_PTR_IN_COPYAREA(manyobjs_ptr, obj_num)
Definition: locator.h:51
MOP locator_add_root(OID *root_oid, MOBJ class_root)
Definition: locator_cl.c:5544
#define BOOT_IS_CLIENT_RESTARTED()
Definition: boot_cl.h:42
static int class_type(DB_OBJECT *class_obj)
Definition: cas_execute.c:8143
void locator_clear_oid_set(THREAD_ENTRY *thread_p, LC_OIDSET *oidset)
Definition: locator.c:2153
void(* LC_OIDMAP_CALLBACK)(LC_OIDMAP *map)
Definition: locator_cl.h:130
OID * ws_oid(MOP mop)
Definition: work_space.c:2884
int locator_get_reserved_class_name_oid(const char *classname, OID *class_oid)
int locator_get_cache_coherency_number(MOP mop)
Definition: locator_cl.c:2171
int locator_fetch_lockhint_classes(LC_LOCKHINT *lockhint, LC_COPYAREA **fetch_copyarea)
#define WS_ISVID(mop)
Definition: work_space.h:288
#define OID_SET_NULL(oidp)
Definition: oid.h:85
void locator_free_lockhint(LC_LOCKHINT *lockhint)
Definition: locator.c:1765
void ws_set_mop_fetched_with_current_snapshot(MOP mop)
Definition: work_space.c:5013
TF_STATUS tf_class_to_disk(MOBJ classobj, RECDES *record)
void locator_synch_isolation_incons(void)
Definition: locator_cl.c:6171
int locator_fetch(OID *oidp, int chn, LOCK lock, LC_FETCH_VERSION_TYPE fetch_version_type, OID *class_oid, int class_chn, int prefetch, LC_COPYAREA **fetch_copyarea)
char * data
void log_set_interrupt(int set)
MOP locator_find_class(const char *classname)
Definition: locator_cl.c:3142
int ws_update_oid_and_class(MOP mop, OID *new_oid, OID *new_class_oid)
Definition: work_space.c:1096
MOBJ locator_fetch_class_of_instance(MOP inst_mop, MOP *class_mop, DB_FETCH_MODE purpose)
Definition: locator_cl.c:2354
enum lc_prefetch_flags LC_PREFETCH_FLAGS
Definition: locator.h:339
static int locator_instance_decache(MOP mop, void *ignore)
Definition: locator_cl.c:5841
MOBJ locator_has_heap(MOP class_mop)
Definition: locator_cl.c:5761
LC_LOCKSET_REQOBJ * objects
Definition: locator.h:305
int er_errid(void)
#define PTR_ALIGN(addr, boundary)
Definition: memory_alloc.h:77
#define WS_MOP_SET_COMPOSITION_FETCH(mop)
Definition: work_space.h:344
void locator_free_lockset(LC_LOCKSET *lockset)
Definition: locator.c:1140
int locator_update_tree_classes(MOP *classes_mop_set, int num_classes)
void locator_free_list_mops(LIST_MOPS *mops)
Definition: locator_cl.c:2978
#define WS_ISDIRTY(mop)
Definition: work_space.h:259
#define er_log_debug(...)
LIST_MOPS * locator_get_all_mops(MOP class_mop, DB_FETCH_MODE purpose, LC_FETCH_VERSION_TYPE *force_fetch_version_type)
Definition: locator_cl.c:2839
LC_OBJTYPE
Definition: locator_cl.h:70
#define WS_ISPINNED(mop)
Definition: work_space.h:310
MOBJ locator_prepare_rename_class(MOP class_mop, const char *old_classname, const char *new_classname)
Definition: locator_cl.c:5975
MOP locator_add_instance(MOBJ instance, MOP class_mop)
Definition: locator_cl.c:5782
bool ws_is_same_object(MOP mop1, MOP mop2)
Definition: work_space.c:5065
int ws_map_class(MOP class_op, MAPFUNC function, void *args)
Definition: work_space.c:2118
int packed_pkey_value_length
Definition: work_space.h:85
static int locator_lock_nested(MOP mop, LOCK lock, int prune_level, int quit_on_errors, int(*fun)(LC_LOCKSET *req, void *args), void *args)
Definition: locator_cl.c:1428
#define MAX_ALIGNMENT
Definition: memory_alloc.h:70
#define COPY_OID(dest_oid_ptr, src_oid_ptr)
Definition: oid.h:63
static int locator_lock_set(int num_mops, MOP *vector_mop, LOCK reqobj_inst_lock, LOCK reqobj_class_lock, int quit_on_errors)
Definition: locator_cl.c:868
LC_OIDMAP * locator_add_oid_set(THREAD_ENTRY *thread_p, LC_OIDSET *set, HFID *heap, OID *class_oid, OID *obj_oid)
Definition: locator.c:2255
int length
Definition: locator.h:248
LOCK reqobj_inst_lock
Definition: locator.h:292
#define OR_MVCC_MAX_HEADER_SIZE
#define LC_UPDATE_OPERATION_TYPE(p)
Definition: locator_cl.h:58
LC_FETCH_VERSION_TYPE fetch_version_type
Definition: locator_cl.c:97
int heap_destroy_newly_created(const HFID *hfid, const OID *class_oid)
LOCATOR_MFLUSH_TEMP_OID * mop_uoids
Definition: locator_cl.c:75
LC_OIDMAP * locator_add_oidset_object(LC_OIDSET *oidset, MOP obj_mop)
Definition: locator_cl.c:6629
LC_CLASS_OIDSET * classes
Definition: locator.h:386
static void locator_keep_mops(MOP mop, MOBJ object, void *kmops)
Definition: locator_cl.c:2598
MOP ws_cache_with_oid(MOBJ obj, OID *oid, MOP class_mop)
Definition: work_space.c:2675
static int locator_save_nested_mops(LC_LOCKSET *lockset, void *save_mops)
Definition: locator_cl.c:2878
LOCK locator_fetch_mode_to_lock(DB_FETCH_MODE purpose, LC_OBJTYPE type, LC_FETCH_VERSION_TYPE fetch_version_type)
Definition: locator_cl.c:2068
void er_stack_pop_and_keep_error(void)
static int locator_get_rest_objects_classes(LC_LOCKSET *lockset, MOP class_mop, MOBJ class_obj)
Definition: locator_cl.c:1333
LOCK
LC_FIND_CLASSNAME locator_find_class_oid(const char *class_name, OID *class_oid, LOCK lock)
MOBJ locator_fetch_class(MOP class_mop, DB_FETCH_MODE purpose)
Definition: locator_cl.c:2293
void ws_add_classname(MOBJ classobj, MOP classmop, const char *cl_name)
Definition: work_space.c:2212
#define OID_INIT_TEMPID()
Definition: oid.h:43
static void locator_mflush_reset(LOCATOR_MFLUSH_CACHE *mflush)
Definition: locator_cl.c:3834
MOBJ locator_fetch_object(MOP mop, DB_FETCH_MODE purpose, LC_FETCH_VERSION_TYPE fetch_version_type)
Definition: locator_cl.c:2235
void mht_destroy(MHT_TABLE *ht)
Definition: memory_hash.c:1140
#define LC_RECDES_TO_GET_ONEOBJ(copy_area_ptr, oneobj_ptr, recdes_ptr)
Definition: locator.h:54
TRAN_ISOLATION isolation
Definition: locator_cl.c:93
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
bool has_index
Definition: work_space.h:86
void ws_set_repl_error_into_error_link(LC_COPYAREA_ONEOBJ *obj, char *content_ptr)
Definition: work_space.c:4944
const char * sm_ch_name(const MOBJ clobj)
static bool locator_can_skip_fetch_from_server(MOP mop, LOCK *lock, LC_FETCH_VERSION_TYPE fetch_version_type)
Definition: locator_cl.c:6899
#define assert(x)
#define ER_LC_PARTIALLY_FAILED_TO_FLUSH
Definition: error_code.h:1394
static int locator_mem_to_disk(LOCATOR_MFLUSH_CACHE *mflush, MOBJ object, bool *has_index, int *round_length_p, WS_MAP_STATUS *map_status)
Definition: locator_cl.c:4395
#define ER_LC_UNKNOWN_CLASSNAME
Definition: error_code.h:121
int32_t fileid
Definition: dbtype_def.h:886
#define ER_GENERIC_ERROR
Definition: error_code.h:49
int au_fetch_class(MOP op, SM_CLASS **class_ptr, AU_FETCHMODE fetchmode, DB_AUTH type)
#define OID_IS_ROOTOID(oidp)
Definition: oid.h:82
struct db_object * class_mop
Definition: work_space.h:121
void ws_free_repl_obj(WS_REPL_OBJ *obj)
Definition: work_space.c:5361
void ws_cache(MOBJ obj, MOP mop, MOP class_mop)
Definition: work_space.c:2575
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
#define TF_ERROR
Definition: transform_cl.h:47
LC_COPYAREA * copy_area
Definition: locator_cl.c:71
int or_chn(RECDES *record)
MOBJ tf_disk_to_class(OID *oid, RECDES *record)
#define OID_ISTEMP(oidp)
Definition: oid.h:80
static int locator_decache_lock(MOP mop, void *ignore)
Definition: locator_cl.c:3278
HFID * sm_ch_heap(MOBJ clobj)
int tf_object_size(MOBJ classobj, MOBJ obj)
void locator_set_sig_interrupt(int set)
Definition: locator_cl.c:193
LC_COPYAREA * locator_allocate_copy_area_by_length(int min_length)
Definition: locator.c:407
static int locator_add_to_oidset_when_temp_oid(MOP mop, void *data)
Definition: locator_cl.c:6753
int locator_flush_class(MOP class_mop)
Definition: locator_cl.c:5068
DB_TRAN_ISOLATION
Definition: dbtran_def.h:26
static void locator_cache_lock(MOP mop, MOBJ ignore_notgiven_object, void *xcache_lock)
Definition: locator_cl.c:309
#define HFID_SET_NULL(hfid)
#define OID_EQ(oidp1, oidp2)
Definition: oid.h:92
VID_OID oid_info
Definition: work_space.h:120
int last_reqobj_cached
Definition: locator.h:290
MOP ws_class_mop(MOP mop)
Definition: work_space.c:2907
int locator_flush_replication_info(REPL_INFO *repl_info)
Definition: locator_cl.c:6869
VFID vfid
void locator_remove_instance(MOP mop)
Definition: locator_cl.c:5916
#define DB_SIZEOF(val)
Definition: memory_alloc.h:54
int tran_abort_only_client(bool is_server_down)
#define OR_MVCC_INSERT_HEADER_SIZE
int locator_assign_all_permanent_oids(void)
Definition: locator_cl.c:6836
#define WS_SET_DELETED(mop)
Definition: work_space.h:286
void * mht_get(MHT_TABLE *ht, const void *key)
Definition: memory_hash.c:1419
int locator_assign_oidset(LC_OIDSET *oidset, LC_OIDMAP_CALLBACK callback)
Definition: locator_cl.c:6687
#define NULL
Definition: freelistheap.h:34
OID oid
Definition: work_space.h:65
struct lc_oidmap * next
Definition: locator.h:346
int heap_create(HFID *hfid, const OID *class_oid, bool reuse_oid)
LOCK ws_get_lock(MOP mop)
Definition: work_space.c:2942
#define LC_EXIST
if(extra_options)
Definition: dynamic_load.c:958
#define LC_NEXT_ONEOBJ_PTR_IN_COPYAREA(oneobj_ptr)
Definition: locator.h:48
LC_FIND_CLASSNAME
int vid_flush_all_instances(MOP class_mop, bool decache)
OID * sm_ch_rep_dir(MOBJ clobj)
#define ONE_MFLUSH
Definition: locator_cl.h:45
int TF_STATUS
Definition: transform_cl.h:37
struct lc_class_oidset * next
Definition: locator.h:365
#define TM_TRAN_READ_FETCH_VERSION()
#define DONT_DECACHE
Definition: locator_cl.h:49
LC_OIDSET * locator_make_oid_set(void)
Definition: locator.c:2116
MHT_TABLE * mht_create(const char *name, int est_size, unsigned int(*hash_func)(const void *key, unsigned int ht_size), int(*cmp_func)(const void *key1, const void *key2))
Definition: memory_hash.c:894
int locator_assign_oid(const HFID *hfid, OID *perm_oid, int expected_length, OID *class_oid, const char *class_name)
static int locator_mflush_reallocate_copy_area(LOCATOR_MFLUSH_CACHE *mflush, int minsize)
Definition: locator_cl.c:3858
MOBJ locator_fetch_nested(MOP mop, DB_FETCH_MODE purpose, int prune_level, int quit_on_errors)
Definition: locator_cl.c:2549
LOCK lock
Definition: work_space.h:134
#define WS_CHN(obj)
Definition: work_space.h:309
unsigned int oid_hash(const void *key_oid, unsigned int htsize)
Definition: oid.c:294
MOBJ locator_fetch_instance(MOP mop, DB_FETCH_MODE purpose, LC_FETCH_VERSION_TYPE fetch_version_type)
Definition: locator_cl.c:2393
#define NULL_FILEID
#define WS_MOP_GET_PRUNE_LEVEL(mop)
Definition: work_space.h:360
static int locator_lock(MOP mop, LC_OBJTYPE isclass, LOCK lock, LC_FETCH_VERSION_TYPE fetch_version_type)
Definition: locator_cl.c:596
static int locator_check_object_and_get_class(MOP obj_mop, MOP *out_class_mop)
Definition: locator_cl.c:6572
LC_FIND_CLASSNAME locator_reserve_class_names(const int num_classes, const char **class_names, OID *class_oids)
static int locator_cache_not_have_object(MOP *mop_p, MOBJ *object_p, bool *call_fun, LC_COPYAREA_ONEOBJ *obj)
Definition: locator_cl.c:3493
struct db_objlist * next
Definition: dbtype_def.h:442
int vid_allflush(void)
void ws_disconnect_deleted_instances(MOP classop)
Definition: work_space.c:1230
MOBJ locator_update_instance(MOP mop)
Definition: locator_cl.c:6035
#define MANY_MFLUSHES
Definition: locator_cl.h:46
static LC_FIND_CLASSNAME locator_find_class_by_name(const char *classname, LOCK lock, MOP *class_mop)
Definition: locator_cl.c:3080
void ws_update_oid(MOP mop, OID *newoid)
Definition: work_space.c:1154
static LIST_MOPS * locator_fun_get_all_mops(MOP class_mop, DB_FETCH_MODE purpose, int(*fun)(MOBJ class_obj), LC_FETCH_VERSION_TYPE *force_fetch_version_type)
Definition: locator_cl.c:2645
void locator_free_oid_set(THREAD_ENTRY *thread_p, LC_OIDSET *oidset)
Definition: locator.c:2227
LC_OIDMAP * oids
Definition: locator.h:366
int total_oids
Definition: locator.h:384
static void locator_cache_lock_set(MOP mop, MOBJ ignore_notgiven_object, void *xlockset)
Definition: locator_cl.c:418
void er_stack_pop(void)
int num_reqobjs
Definition: locator.h:287
void ws_drop_classname(MOBJ classobj)
Definition: work_space.c:2247
#define LC_RECDES_IN_COPYAREA(copy_area_ptr, recdes_ptr)
Definition: locator.h:74
int oid_compare_equals(const void *key_oid1, const void *key_oid2)
Definition: oid.c:310
int ws_Error_ignore_list[-ER_LAST_ERROR]
Definition: work_space.c:160
int ws_mop_compare(MOP mop1, MOP mop2)
Definition: work_space.c:3144
int locator_flush_instance(MOP mop)
Definition: locator_cl.c:5236
struct db_object * op
Definition: dbtype_def.h:443
#define CAST_BUFLEN
Definition: porting.h:471
int locator_get_class(OID *class_oid, int class_chn, const OID *oid, LOCK lock, int prefetching, LC_COPYAREA **fetch_copyarea)
MOP locator_find_class_with_purpose(const char *classname, bool for_update)
Definition: locator_cl.c:3167
LIST_MOPS * locator_get_all_class_mops(DB_FETCH_MODE purpose, int(*fun)(MOBJ class_obj))
Definition: locator_cl.c:2861
static void error(const char *msg)
Definition: gencat.c:331
void ws_set_lock(MOP mop, LOCK lock)
Definition: work_space.c:2954
static void locator_mflush_end(LOCATOR_MFLUSH_CACHE *mflush)
Definition: locator_cl.c:3896
int locator_repl_flush_all(void)
Definition: locator_cl.c:5500
entry_workpool * instance
LC_COPYAREA_ONEOBJ * obj
Definition: locator_cl.c:73
int locator_decache_all_lock_instances(MOP class_mop)
Definition: locator_cl.c:3293
#define HFID_IS_NULL(hfid)
int locator_does_exist_object(MOP mop, DB_FETCH_MODE purpose)
Definition: locator_cl.c:3242
OID * locator_assign_permanent_oid(MOP mop)
Definition: locator_cl.c:6084
#define AU_SELECT
Definition: authenticate.h:69
#define ER_LC_CLASSNAME_EXIST
Definition: error_code.h:122
LC_COPYAREA_OPERATION
Definition: locator.h:106
#define ARG_FILE_LINE
Definition: error_manager.h:44
int sm_partitioned_class_type(DB_OBJECT *classop, int *partition_type, char *keyattr, MOP **partitions)
int locator_remove_class(MOP class_mop)
Definition: locator_cl.c:5858
void ws_decache(MOP mop)
Definition: work_space.c:2701
#define WS_OID(mop)
Definition: work_space.h:293
int locator_all_flush(void)
Definition: locator_cl.c:5457
#define AU_ENABLE(save)
Definition: authenticate.h:113
LC_FIND_CLASSNAME locator_lockhint_classes(int num_classes, const char **many_classnames, LOCK *many_locks, int *need_subclasses, LC_PREFETCH_FLAGS *flags, int quit_on_errors, LOCK lock_rr_tran)
Definition: locator_cl.c:6260
int sm_class_has_unique_constraint(MOBJ classobj, MOP classop, bool check_subclasses, bool *has_unique)
int(* fun)(MOBJ class_obj)
Definition: locator_cl.c:109
int vid_flush_instance(MOP mop, void *arg)
void * object
Definition: work_space.h:123
#define free_and_init(ptr)
Definition: memory_alloc.h:147
unsigned char pruning_type
Definition: work_space.h:138
#define LC_ONEOBJ_SET_HAS_INDEX(obj)
Definition: locator.h:203
bool sm_is_reuse_oid_class(MOP op)
LC_FIND_CLASSNAME locator_reserve_class_name(const char *class_name, OID *class_oid)
Definition: locator_cl.c:179
#define ER_OBJ_INVALID_ARGUMENTS
Definition: error_code.h:275
static void locator_cache_lock_lockhint_classes(LC_LOCKHINT *lockhint)
Definition: locator_cl.c:6209
#define DB_WASTED_ALIGN(offset, align)
Definition: memory_alloc.h:90
#define DB_PAGESIZE
int ws_map_dirty(MAPFUNC function, void *args)
Definition: work_space.c:1849
MOP mops[1]
Definition: locator_cl.h:67
#define ER_HEAP_UNKNOWN_OBJECT
Definition: error_code.h:102
#define INT_ALIGNMENT
Definition: memory_alloc.h:61
#define LC_MANYOBJS_PTR_IN_COPYAREA(copy_areaptr)
Definition: locator.h:39
MOP ws_find_class(const char *name)
Definition: work_space.c:2278
int locator_force(LC_COPYAREA *copy_area, int num_ignore_error_list, int *ignore_error_list, int content_size)
#define OID_BATCH_SIZE
Definition: locator_cl.h:51
LOCATOR_MFLUSH_TEMP_OID * next
Definition: locator_cl.c:65
LC_FIND_CLASSNAME locator_delete_class_name(const char *class_name)
LC_FIND_CLASSNAME locator_rename_class_name(const char *old_name, const char *new_name, OID *class_oid)
#define IS_WRITE_EXCLUSIVE_LOCK(lock)
LOCK lock_Conv[12][12]
Definition: lock_table.c:179
OID oid
Definition: locator.h:352
int locator_fetch_all(const HFID *hfid, LOCK *lock, LC_FETCH_VERSION_TYPE fetch_version_type, OID *class_oidp, int *nobjects, int *nfetched, OID *last_oidp, LC_COPYAREA **fetch_copyarea)
int locator_flush_for_multi_update(MOP class_mop)
Definition: locator_cl.c:5401
int locator_fetch_all_reference_lockset(OID *oid, int chn, OID *class_oid, int class_chn, LOCK lock, int quit_on_errors, int prune_level, LC_LOCKSET **lockset, LC_COPYAREA **fetch_copyarea)
DB_OBJLIST * users
Definition: class_object.h:712
int i
Definition: dynamic_load.c:954
#define DECACHE
Definition: locator_cl.h:48
int locator_flush_all_instances(MOP class_mop, bool decache)
Definition: locator_cl.c:5278
void * mop
Definition: locator.h:349
#define ER_LC_LOCK_CACHE_ERROR
Definition: error_code.h:1053
static int locator_cache_object_instance(MOP mop, MOP class_mop, MOP *hint_class_mop_p, MOBJ *hint_class_p, LC_COPYAREA_ONEOBJ *obj, MOBJ *object_p, RECDES *recdes_p, bool *call_fun)
Definition: locator_cl.c:3406
static int locator_set_chn_classes_objects(LC_LOCKSET *lockset)
Definition: locator_cl.c:1271
MOBJ locator_update_class(MOP mop)
Definition: locator_cl.c:5938
static LOCK locator_to_prefetched_lock(LOCK class_lock)
Definition: locator_cl.c:387
static int locator_lock_and_doesexist(MOP mop, LOCK lock, LC_OBJTYPE isclass)
Definition: locator_cl.c:1841
LC_COPYAREA_MANYOBJS * mobjs
Definition: locator_cl.c:72
static int locator_repl_mflush(LOCATOR_MFLUSH_CACHE *mflush)
Definition: locator_cl.c:4952
int repl_log_get_append_lsa(LOG_LSA *lsa)
int num_classes_of_reqobjs_processed
Definition: locator.h:297
DB_FETCH_MODE
Definition: dbtype_def.h:215
bool do_Trigger_involved
MOP sm_Root_class_mop
#define LC_INSERT_OPERATION_TYPE(p)
Definition: locator_cl.h:53
#define OID_ISNULL(oidp)
Definition: oid.h:81
int locator_is_class(MOP mop, DB_FETCH_MODE hint_purpose)
Definition: locator_cl.c:239
int operation
Definition: work_space.h:87
int num_classes_of_reqobjs
Definition: locator.h:296
#define LC_ONEOBJ_SET_HAS_UNIQUE_INDEX(obj)
Definition: locator.h:206
bool locator_is_root(MOP mop)
Definition: locator_cl.c:212
LOCK reqobj_class_lock
Definition: locator.h:293
bool ws_is_mop_fetched_with_current_snapshot(MOP mop)
Definition: work_space.c:5000
#define LC_IS_FLUSH_INSERT(operation)
Definition: locator.h:121
int num_reqobjs_processed
Definition: locator.h:289
static int locator_repl_mflush_force(LOCATOR_MFLUSH_CACHE *mflush)
Definition: locator_cl.c:3992
LC_LOCKSET * locator_allocate_lockset(int max_reqobjs, LOCK reqobj_inst_lock, LOCK reqobj_class_lock, int quit_on_errors)
Definition: locator.c:955
int ws_find(MOP mop, MOBJ *obj)
Definition: work_space.c:3112
static void locator_repl_mflush_check_error(LC_COPYAREA *mflush)
Definition: locator_cl.c:4037
#define WS_MOP_GET_COMPOSITION_FETCH(mop)
Definition: work_space.h:341
static int locator_mflush(MOP mop, void *mf)
Definition: locator_cl.c:4507
#define TF_SUCCESS
Definition: transform_cl.h:45
int num_classes
Definition: locator.h:324
#define ER_LC_NOHEAP
Definition: error_code.h:124
static int locator_cache_have_object(MOP *mop_p, MOBJ *object_p, RECDES *recdes_p, MOP *hint_class_mop_p, MOBJ *hint_class_p, bool *call_fun, LC_COPYAREA_ONEOBJ *obj)
Definition: locator_cl.c:3589
#define HFID_COPY(hfid_ptr1, hfid_ptr2)
LC_COPYAREA_OPERATION operation
Definition: locator.h:219
int last_classof_reqobjs_cached
Definition: locator.h:298
LC_LOCKHINT_CLASS * classes
Definition: locator.h:329
static int locator_cache_object_class(MOP mop, LC_COPYAREA_ONEOBJ *obj, MOBJ *object_p, RECDES *recdes_p, bool *call_fun)
Definition: locator_cl.c:3319
#define TM_TRAN_ISOLATION()
MOP locator_add_class(MOBJ class_obj, const char *classname)
Definition: locator_cl.c:5595
HFID * sm_Root_class_hfid
#define ER_LC_UNEXPECTED_PERM_OID
Definition: error_code.h:898
TF_STATUS tf_mem_to_disk(MOP classmop, MOBJ classobj, MOBJ volatile obj, RECDES *record, bool *index_flag)
Definition: transform_cl.c:767