00001 /*<std-header orig-src='shore' incl-file-exclusion='VTABLE_INFO_H'> 00002 00003 $Id: vtable.h,v 1.4 2010/07/07 20:50:12 nhall Exp $ 00004 00005 SHORE -- Scalable Heterogeneous Object REpository 00006 00007 Copyright (c) 1994-99 Computer Sciences Department, University of 00008 Wisconsin -- Madison 00009 All Rights Reserved. 00010 00011 Permission to use, copy, modify and distribute this software and its 00012 documentation is hereby granted, provided that both the copyright 00013 notice and this permission notice appear in all copies of the 00014 software, derivative works or modified versions, and any portions 00015 thereof, and that both notices appear in supporting documentation. 00016 00017 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY 00018 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS 00019 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND 00020 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 00021 00022 This software was developed with support by the Advanced Research 00023 Project Agency, ARPA order number 018 (formerly 8230), monitored by 00024 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518. 00025 Further funding for this work was provided by DARPA through 00026 Rome Research Laboratory Contract No. F30602-97-2-0247. 00027 00028 */ 00029 00030 #ifndef VTABLE_INFO_H 00031 #define VTABLE_INFO_H 00032 00033 #include "w_defines.h" 00034 00035 /* -- do not edit anything above this line -- </std-header>*/ 00036 00037 /* skip documentation for this for now. */ 00038 00039 #include <cstring> 00040 00041 /**\brief Structure for converting arbitrary info to a row of a virtual table. 00042 * 00043 * \details 00044 * A datum in a virtual table is an 64-byte string. 00045 * The strings usually take the form "name value". 00046 * A vtable_row_t is an array of these data, and represents a row in 00047 * a virtual table. 00048 * It is a structure "imposed" on an already-allocated block of data. 00049 * This struct 00050 * does NOT allocate or deallocate anything. 00051 * 00052 * Each "attribute" or entry of the row is identified by an integer. 00053 */ 00054 class vtable_row_t { 00055 private: 00056 int N; 00057 int M; // max value size 00058 int _in_use; 00059 char *_list; 00060 char *_list_end; 00061 char *_entry[1]; 00062 00063 public: 00064 // Must construct a row with at least 1 attribute. 00065 NORET vtable_row_t() : N(0), M(0), _in_use(0), _list(NULL), 00066 _list_end(NULL) { dump("construct"); } 00067 NORET ~vtable_row_t() { } 00068 00069 /// Number of attributes in the row. 00070 int quant() const { return _in_use; } 00071 00072 // vtable_t needs to make sure this doesn't exceed the space 00073 // it allocated. 00074 char *end() const { return _list_end; } 00075 int size_in_bytes() const { return _list_end - (char *)this; } 00076 00077 /// Return # bytes user must allocate to accommodate n attributes of 00078 /// m bytes each plus whatever overhead we have in this structure. 00079 static int bytes_required_for(int n, int m) { 00080 return 00081 sizeof(vtable_row_t) 00082 + (n-1) * sizeof(char * /*_entry[0]*/) 00083 + (n * m); 00084 } 00085 int value_size() const { return M; } 00086 00087 /// Initialize a row for n attributes. Must be at least 1. 00088 /// Assumes we have enough space for this to happen. 00089 /// User of this row must have allocated enough space. 00090 /// Let the maximum value size be m. 00091 void init_for_attributes(int n, int m) 00092 { 00093 w_assert0(n>0); 00094 N = n; 00095 M = m; 00096 00097 // had better have been allocated by caller. 00098 memset(&_entry[0], '\0', n * m + 00099 + (n*sizeof(_entry[0]))); 00100 00101 _in_use=0; 00102 _list = (char *)&_entry[N]; // one past the last _entry 00103 _list_end = _list; // none in use 00104 _entry[0] = _list; 00105 00106 #if W_DEBUG_LEVEL > 3 00107 // had better have been initialized by caller 00108 for(int a=0; a<n; a++) { 00109 w_assert3(strlen(_get_const(a)) == 0); 00110 } 00111 #endif 00112 w_assert1(size_in_bytes() <= bytes_required_for(n,m)); 00113 } 00114 00115 /// realloc for larger number of attributes. This means we 00116 /// have to shift around the values. We don't allow change of 00117 /// maximum value size (M) 00118 void reinit_for_attributes(int n) 00119 { 00120 int additional = n - N; 00121 if(additional > 0) { 00122 int bytes = sizeof(_entry[0]) * additional; 00123 00124 // move the data. args: dest, src, amt 00125 memmove(&_list[additional], &_list[0], bytes); 00126 for(int i=N; i < n; i++) { 00127 _entry[i] = 0; 00128 } 00129 _list = &_list[bytes]; 00130 _list_end = &_list_end[bytes]; 00131 // _in_use doesn't change. 00132 } 00133 } 00134 00135 /// Convert the unsigned int to a string datum at the location for \e a. 00136 void set_uint(int a, unsigned int v); 00137 /// Convert the int to a string datum at the location for \e a. 00138 void set_int(int a, int v); 00139 /// Convert the base_stat_t to a string datum at the location for \e a. 00140 void set_base(int a, w_base_t::base_stat_t v); 00141 /// Convert the base_float_t to a string datum at the location for \e a. 00142 void set_base(int a, w_base_t::base_float_t v); 00143 /// Copy the string to a string datum at the location for \e a. 00144 void set_string(int a, const char *v); 00145 00146 /// Return whatever string is already written to the location for \e a. 00147 const char *operator[](int a) const { 00148 return _get_const(a); 00149 } 00150 00151 00152 ostream& operator<<(ostream &o); 00153 /// Return the number of entries/locations/attributes for this "row". 00154 int n() const { return N; } 00155 00156 void dump(const char *msg)const; 00157 private: 00158 vtable_row_t(const vtable_row_t&); // disabled 00159 vtable_row_t& operator=(const vtable_row_t&); // disabled 00160 /// From a given int a, return a pointer to the entry 00161 /// for that int so that we can stuff something into 00162 /// that entry. NO ALIGNMENT! 00163 char *_insert_attribute(int a) { 00164 w_assert1(a < N); 00165 w_assert1(a >= 0); 00166 char * v = (char *)_entry[a]; 00167 if(v==NULL) { 00168 v = (_entry[a] = _list_end); 00169 } 00170 return v; 00171 } 00172 00173 const char *_get_const(int a) const { 00174 const char *x = (const char *)_entry[a]; 00175 w_assert1(x < _list_end); 00176 return x; 00177 } 00178 00179 /// Notify the row that we inserted something in attribute #a. 00180 void _inserted(int a); 00181 }; 00182 00183 /**\brief Structure for converting lower layer info to a virtual table. 00184 * \details 00185 * This structure holds a set of vtable_row_t, which is a set of attributes. 00186 * The space for the whole mess is allocated by the vtable_t, and the rows 00187 * must be populated strictly in sequence, and the attributes of the rows 00188 * likewise must be populated in sequence. As a row is populated, 00189 * space for the attributes is peeled off the chunk allocated by the vtable. 00190 * The idea here is to create, without undue heap activity, a 00191 * string-based (untyped) 00192 * virtual table containing various and sundry information. 00193 * The things that can be gathered and stuffed into virtual tables include: 00194 * Info about the threads, transactions. 00195 * A server could, if it so chose, convert this information into a 00196 * relational table. 00197 * Originally this was used to send across the wire, via RPC, this info 00198 * to a client in client/server SHORE. Now it has been stripped down. 00199 * Someday if this facility proves useful, we should make 00200 * this collect typed information so that the attributes 00201 * can be int or double. But for now, they are string representations of the 00202 * values. 00203 * 00204 * Test programs may use ss_m::xct_collect(vtable &) and kin, 00205 * and output the results with the operator<< for vtable_t. 00206 */ 00207 class vtable_t { 00208 public: 00209 NORET vtable_t() : _rows(0), _rows_filled(0), 00210 _rowsize_attributes(0), _rowsize_bytes(0), 00211 _array_alias(NULL) {} 00212 00213 /// Initialize table with \e R rows, with up to \e A attributes, 00214 /// each with a maximum size of \e S bytes. 00215 int init(int R, int A, int S); 00216 00217 NORET ~vtable_t() { 00218 delete[] _array_alias; 00219 _array_alias = NULL; 00220 } 00221 00222 vtable_row_t& operator[] (int i) const { 00223 // called by updater so can't use this assertion 00224 // w_assert1(i < _rows_filled); 00225 return *_get_row(i); 00226 } 00227 00228 ostream& operator<<(ostream &o) const; 00229 00230 /// Return number of rows filled. 00231 int quant() const { return _rows_filled; } 00232 int size() const { return _rows; } 00233 void filled_one(); 00234 void back_out(int n) { _rows_filled -= n; } 00235 int realloc(); 00236 private: 00237 vtable_t(const vtable_t&); // disabled 00238 vtable_t& operator=(const vtable_t&); // disabled 00239 00240 vtable_row_t* _get_row(int i) const; 00241 00242 int _rows; 00243 int _rows_filled; 00244 int _rowsize_attributes; //#strings 00245 int _rowsize_bytes;//#string * sizeof string 00246 char* _array_alias; 00247 00248 }; 00249 00250 /**\brief Template class for converting lower layer info to a virtual table. 00251 * \details 00252 * This function is called for each entity that will be represented by 00253 * a row in a virtual table. 00254 * We construct it with an entire virtual table, which must have been 00255 * pre-allocated with the right number for rows, N. TODO FIX 00256 * 00257 * Then we invoke it (call its operator ()) N times, passing in 00258 * each time a reference to the entity (of type T) we want it to "convert" to 00259 * a row. 00260 * Each class T whose instances are to be represented in 00261 * a virtual table must have a method 00262 * \code 00263 T::vtable_collect(vtable_row_t &) 00264 * \endcode 00265 */ 00266 template <class T> 00267 class vtable_func 00268 { 00269 public: 00270 NORET vtable_func(vtable_t &v): _curr(0), _array(v) { } 00271 NORET ~vtable_func() { } 00272 00273 void insert_names() { 00274 T::vtable_collect_names(_array[_curr]); 00275 _array.filled_one(); 00276 w_assert9(_curr < _array.size()); 00277 _curr++; 00278 } 00279 /// Gather information about t and stuff it into row @ index _curr. 00280 /// It gathers by calling the T::vtable_collect(vtable_row_t &) 00281 void operator()(const T& t) // gather func 00282 { 00283 // escape the const-ness if possible 00284 T &t2 = (T &)t; 00285 t2.vtable_collect( _array[_curr] ); 00286 00287 // bump its counter 00288 _array.filled_one(); 00289 w_assert9(_curr < _array.size()); 00290 _curr++; 00291 } 00292 /// Un-collect the last \e n entries. 00293 void back_out(int n) { 00294 _curr -= n; 00295 _array.back_out(n); 00296 } 00297 00298 int realloc() { 00299 return _array.realloc(); 00300 } 00301 00302 protected: 00303 int _curr; 00304 vtable_t& _array; // uses vtable_t::operator[] 00305 }; 00306 00307 00308 /**\cond skip */ 00309 class vtable_names_init_t { 00310 size_t _size; 00311 int _argc; 00312 const char * const * _argv; 00313 public: 00314 NORET vtable_names_init_t(int argc, const char *const argv[]) : _size(0), 00315 _argc(argc), _argv(argv) 00316 { 00317 // Let _size be the larger of sizeof(double) and the 00318 // the longest string name of the sthread vtable 00319 // attributes. The minimum being sizeof(double) is so that 00320 // we can ultimately have these attribute be typed rather than 00321 // all strings. 00322 int mx=0; 00323 for(int i=0; i < _argc; i++) { 00324 if(_argv[i]==NULL) break; 00325 int j = strlen(_argv[i]); 00326 if(j > mx) mx = j; 00327 } 00328 _size = size_t(mx)+1; // leave room for trailing null. 00329 if(_size < sizeof(double)) _size = sizeof(double); 00330 } 00331 const char *name(int i) const { 00332 return _argv[i]; 00333 } 00334 void collect_names(vtable_row_t &t) { 00335 for(int i=0; i < _argc; i++) 00336 { 00337 if(_argv[i]) t.set_string(i, _argv[i]); 00338 } 00339 } 00340 int max_size() const { return int(_size); } 00341 }; 00342 /**\endcond skip */ 00343 00344 /*<std-footer incl-file-exclusion='VTABLE_INFO_H'> -- do not edit anything below this line -- */ 00345 00346 #endif /*</std-footer>*/