A platform for high-performance distributed tool and library development written in C++. It can be deployed in two different cluster modes: standalone or distributed. API for v0.5.0, released on June 13, 2018.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Handle.h
Go to the documentation of this file.
1 /*****************************************************************************
2  * *
3  * Copyright 2018 Rice University *
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 #include "Object.h"
20 #include "PDBTemplateBase.h"
21 
22 #ifndef HANDLE_H
23 #define HANDLE_H
24 
25 #include <cstddef>
26 #include <iostream>
27 #include <vector>
28 #include <algorithm>
29 #include <iterator>
30 #include <cstring>
31 
32 namespace pdb {
33 
34 template <class ObjType>
35 class RefCountedObject;
36 
37 #define CHAR_PTR(c) ((char*)c)
38 
39 // A Handle is a pointer-like object that helps with several different tasks:
40 //
41 // (1) It ensures that everything pointed to by the Handle lives in the
42 // same allocation block as the Handle (an allocation block is a
43 // contiguous range of memory)---if the Handle itself lives in an
44 // allocation block. If an assignment could cause this requirement
45 // to be allocated, then a deep copy is automatically performed.
46 //
47 // For example, consider the following:
48 //
49 // class Supervisor : public Object {
50 //
51 // private:
52 //
53 // int salary;
54 // double weight;
55 // Handle <Employee> myEmployee;
56 //
57 // public:
58 //
59 // Supervisor (int salIn, double wgtIn, Handle <Employee> &myEmp) {
60 // salary = salIn;
61 // weight = wgtIn;
62 // myEmployee = myEmp;
63 // }
64 // }
65 //
66 // Then we have:
67 //
68 // makeObjectAllocatorBlock (8192, true);
69 // myEmp = makeObject <Employee> (100, 120);
70 //
71 // makeObjectAllocatorBlock (8192, true);
72 // mySup = makeObject <Supervisor> (134, 124.5, myEmp);
73 //
74 // The assignment "myEmployee = myEmp;" will cause a deep copy to happen,
75 // so that everything inside of the object pointed to by mySup (including
76 // the data pointed to by the member myEmployee) resided in the same allocation
77 // block.
78 //
79 // (2) Handles also act as smart pointers. Whenever there is no longer a way
80 // to reach an Object that is in an allocation block, the Object is deleted.
81 // Whenever an allocation block is no longer active and it has no more reachable
82 // Objects, it is automatically freed.
83 //
84 // (3) Finally, Handles act as offset pointers that can move from one address space
85 // to another without causing any problems. This means that objects that use
86 // Handles can be written to disk and then read back again by another process,
87 // and there won't be any problem.
88 
89 class GenericHandle;
90 
91 // so all instantiated Handle types derive from HandleBase
92 class HandleBase {};
93 
94 // Here is the Handle class....
95 template <class ObjType>
96 class Handle : public HandleBase {
97 
98 private:
99  // where this guy is located
100  int64_t offset;
101 
102  // this is the class that all PDB templates include, so that they can
103  // implement type erasure...
104  PDBTemplateBase typeInfo;
105 
106 public:
107  // makes a null handle
108  Handle();
109 
110  // free memory, as needed
111  ~Handle();
112 
113  // makes a null handle
114  Handle(const std::nullptr_t rhs);
115  Handle<ObjType>& operator=(const std::nullptr_t rhs);
116 
117  // makes a handle out of an GenericHandle object... this is done so that we can initialize the
118  // Handle
119  // object that we send to getSelection or getProjection when setting up a join
120  Handle(GenericHandle rhs);
121 
122  // see if we are null
123  friend bool operator==(const Handle<ObjType>& lhs, std::nullptr_t rhs) {
124  return lhs.isNullPtr();
125  }
126  friend bool operator==(std::nullptr_t rhs, const Handle<ObjType>& lhs) {
127  return lhs.isNullPtr();
128  }
129  friend bool operator!=(std::nullptr_t rhs, const Handle<ObjType>& lhs) {
130  return !lhs.isNullPtr();
131  }
132  friend bool operator!=(const Handle<ObjType>& lhs, std::nullptr_t rhs) {
133  return !lhs.isNullPtr();
134  }
135  bool isNullPtr() const;
136 
137  // a hash on a handle just hashes the underlying object
138  size_t hash() const {
139  return (*this)->hash();
140  }
141 
142  // get the reference count for this Handle, if it exists (returns 99999999 if it does not)
143  unsigned getRefCount();
144 
145  // this finds the allocation block that contains this particular Handle and sets the reference
146  // count to zero,
147  // freeing the allocation block if necessary. Then, this Handle is set to be a nullptr. This
148  // is used at
149  // various times by PDB systems programmers to prevent any sort of recursive deletions in a
150  // block when it RAM
151  // has already been written out... we just call emptyOutContainingBlock () and we are guatanteed
152  // that the block
153  // will be removed. IMPORTANT: this should only be called if this Handle object is the ONLY
154  // reference into
155  // the block. Otherwise, bad things will happen when one of those other references attempts to
156  // look at the
157  // allocation block
159 
160  // makes sure that the data pointed to by *this is located in the current
161  // allocation block. If it is, simply return a copy of *this. If it is not,
162  // copy the item referenced by it to the current allocation block and return
163  // a handle to that item.
164  Handle<ObjType> copyTargetToCurrentAllocationBlock();
165 
166  /***************************************************************************/
167  /* There are eight different cases for assign/copy construction on Handles */
168  /* */
169  /* 1. Copy construct from RefCountedObject of same Object type */
170  /* 2. Copy construct from RefCountedObject of diff Object type */
171  /* 3. Copy construct from Handle of same Object type */
172  /* 4. Copy construct from Handle of diff Object type */
173  /* 5. Assignment from RefCountedObject of same Object type */
174  /* 6. Assignment from RefCountedObject of diff Object type */
175  /* 7. Assignment from Handle of same Object type */
176  /* 8. Assignment from Handle of diff Object type */
177  /***************************************************************************/
178 
179  /***************************************/
180  /* Here are the four copy constructors */
181  /***************************************/
182 
183  /*************************************************************/
184  /* Here are the two copy constructors from RefCountedObjects */
185  /*************************************************************/
186 
187  Handle(const RefCountedObject<ObjType>* fromMe);
188  template <class ObjTypeTwo>
189  Handle(const RefCountedObject<ObjTypeTwo>* fromMe);
190 
191  /***************************************************/
192  /* Here are the two copy constructors from Handles */
193  /***************************************************/
194 
195  Handle(const Handle<ObjType>& fromMe);
196  template <class ObjTypeTwo>
197  Handle(const Handle<ObjTypeTwo>& fromMe);
198 
199  /******************************************/
200  /* Here are the four assignment operators */
201  /******************************************/
202 
203  /****************************************************************/
204  /* Here are the two assignment operators from RefCountedObjects */
205  /****************************************************************/
206 
207  Handle& operator=(const RefCountedObject<ObjType>* fromMe);
208  template <class ObjTypeTwo>
209  Handle& operator=(const RefCountedObject<ObjTypeTwo>* fromMe);
210 
211  /******************************************************/
212  /* Here are the two assignment operators from Handles */
213  /******************************************************/
214 
215  Handle<ObjType>& operator=(const Handle<ObjType>& fromMe);
216  template <class ObjTypeTwo>
217  Handle<ObjType>& operator=(const Handle<ObjTypeTwo>& fromMe);
218 
219  // de-reference operators
220  ObjType* operator->() const;
221  ObjType& operator*() const;
222 
223  // get/set the offset
224  void setOffset(int64_t toMe);
225  int64_t getOffset() const;
226 
227  // get the type code
228  int16_t getTypeCode();
229 
230  // get/set the type code (here, a negative value means not an Object descendent)
231  int32_t getExactTypeInfoValue() const;
232  void setExactTypeInfoValue(int32_t toMe);
233 
234  // gets a pointer to the target object
235  RefCountedObject<ObjType>* getTarget() const;
236 
237  // JiaNote: to shallow copy a handle to current allocation block
238  // This is to improve the performance of current pipeline bundling
239  Handle<ObjType>& shallowCopyToCurrentAllocationBlock(const Handle<ObjType>& copyMe);
240 
241 private:
242  template <class ObjTypeTwo>
243  friend class Handle;
244  // friend Allocator;
245  template <class Obj, class... Args>
246  friend RefCountedObject<Obj>* makeObject(Args&&... args);
247  template <class OutObjType, class InObjType>
248  friend Handle<OutObjType> unsafeCast(Handle<InObjType>& castMe);
249  template <class Obj>
250  friend class Record;
251 };
252 
253 // this weird little class is used to initialize the handle objects that go into getSelection and
254 // getProjection
255 // in a join object
256 class GenericHandle {
257 
258  PDBTemplateBase myBase;
259 
260 public:
261  // in this way, we encode initValue within myBase
262  GenericHandle(int initValue) {
263  myBase.set(-initValue);
264  }
265 
266  GenericHandle() {
267  myBase.set(-1);
268  }
269 
270  PDBTemplateBase& getMyBase() {
271  return myBase;
272  }
273 };
274 
275 // equality on handles checks for equality of the underlying objects...
276 template <class ObjTypeOne, class ObjTypeTwo>
277 bool operator==(const Handle<ObjTypeOne>& lhs, const Handle<ObjTypeTwo>& rhs) {
278  if (lhs.isNullPtr() || rhs.isNullPtr())
279  return false;
280  return *lhs == *rhs;
281 }
282 
283 template <class ObjTypeOne, class ObjTypeTwo>
284 bool operator==(const ObjTypeOne& lhs, const Handle<ObjTypeTwo>& rhs) {
285  if (rhs.isNullPtr())
286  return false;
287  return lhs == *rhs;
288 }
289 
290 template <class ObjTypeOne, class ObjTypeTwo>
291 bool operator==(const Handle<ObjTypeOne>& lhs, const ObjTypeTwo& rhs) {
292  if (lhs.isNullPtr())
293  return false;
294  return *lhs == rhs;
295 }
296 }
297 
298 #include "Handle.cc"
299 
300 #endif
LambdaTree< bool > operator==(LambdaTree< LeftType > lhs, LambdaTree< RightType > rhs)
bool operator!=(const STLSlabAllocator< T > &left, const STLSlabAllocator< U > &right)
RefCountedObject< ObjType > * makeObject(Args &&...args)
Handle< OutObjType > unsafeCast(Handle< InObjType > &castMe)
void emptyOutContainingBlock(void *forMe)