/* Copyright (C) 2021-2024 Free Software Foundation, Inc. Contributed by Oracle. This file is part of GNU Binutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include "IndexMap2D.h" #include "DbeSession.h" #include "FilterExp.h" #include "Table.h" #include "util.h" #include "i18n.h" char * get_prof_data_type_name (int t) { switch (t) { case DATA_SAMPLE: return NTXT("PROFDATA_TYPE_SAMPLE"); case DATA_GCEVENT: return NTXT("PROFDATA_TYPE_GCEVENT"); case DATA_HEAPSZ: return NTXT("PROFDATA_TYPE_HEAPSZ"); case DATA_CLOCK: return NTXT("PROFDATA_TYPE_CLOCK"); case DATA_HWC: return NTXT("PROFDATA_TYPE_HWC"); case DATA_SYNCH: return NTXT("PROFDATA_TYPE_SYNCH"); case DATA_HEAP: return NTXT("PROFDATA_TYPE_HEAP"); case DATA_OMP: return NTXT("PROFDATA_TYPE_OMP"); case DATA_OMP2: return NTXT("PROFDATA_TYPE_OMP2"); case DATA_OMP3: return NTXT("PROFDATA_TYPE_OMP3"); case DATA_OMP4: return NTXT("PROFDATA_TYPE_OMP4"); case DATA_OMP5: return NTXT("PROFDATA_TYPE_OMP5"); case DATA_IOTRACE: return NTXT("PROFDATA_TYPE_IOTRACE"); default: abort (); return NTXT ("PROFDATA_TYPE_ERROR"); } } char * get_prof_data_type_uname (int t) { switch (t) { case DATA_SAMPLE: return GTXT("Process-wide Resource Utilization"); case DATA_GCEVENT: return GTXT("Java Garbage Collection Events"); case DATA_HEAPSZ: return GTXT("Heap Size"); case DATA_CLOCK: return GTXT("Clock Profiling"); case DATA_HWC: return GTXT("HW Counter Profiling"); case DATA_SYNCH: return GTXT("Synchronization Tracing"); case DATA_HEAP: return GTXT("Heap Tracing"); case DATA_OMP: return GTXT("OpenMP Profiling"); case DATA_OMP2: return GTXT("OpenMP Profiling"); case DATA_OMP3: return GTXT("OpenMP Profiling"); case DATA_OMP4: return GTXT("OpenMP Profiling"); case DATA_OMP5: return GTXT("OpenMP Profiling"); case DATA_IOTRACE: return GTXT("IO Tracing"); default: abort (); return NTXT ("PROFDATA_TYPE_ERROR"); } } int assert_level = 0; // set to 1 to bypass problematic asserts #define ASSERT_SKIP (assert_level) /* * class PropDescr */ PropDescr::PropDescr (int _propID, const char *_name) { propID = _propID; name = xstrdup (_name ? _name : NTXT ("")); uname = NULL; vtype = TYPE_NONE; flags = 0; stateNames = NULL; stateUNames = NULL; } PropDescr::~PropDescr () { free (name); free (uname); if (stateNames) { stateNames->destroy (); delete stateNames; } if (stateUNames) { stateUNames->destroy (); delete stateUNames; } } void PropDescr::addState (int value, const char *stname, const char *stuname) { if (value < 0 || stname == NULL) return; if (stateNames == NULL) stateNames = new Vector; stateNames->store (value, xstrdup (stname)); if (stateUNames == NULL) stateUNames = new Vector; stateUNames->store (value, xstrdup (stuname)); } char * PropDescr::getStateName (int value) { if (stateNames && value >= 0 && value < stateNames->size ()) return stateNames->fetch (value); return NULL; } char * PropDescr::getStateUName (int value) { if (stateUNames && value >= 0 && value < stateUNames->size ()) return stateUNames->fetch (value); return NULL; } /* * class FieldDescr */ FieldDescr::FieldDescr (int _propID, const char *_name) { propID = _propID; name = _name ? xstrdup (_name) : NULL; offset = 0; vtype = TYPE_NONE; format = NULL; } FieldDescr::~FieldDescr () { free (name); free (format); } /* * class PacketDescriptor */ PacketDescriptor::PacketDescriptor (DataDescriptor *_ddscr) { ddscr = _ddscr; fields = new Vector; } PacketDescriptor::~PacketDescriptor () { fields->destroy (); delete fields; } void PacketDescriptor::addField (FieldDescr *fldDscr) { if (fldDscr == NULL) return; fields->append (fldDscr); } /* * class Data */ /* Check compatibility between Datum and Data */ static void checkCompatibility (VType_type v1, VType_type v2) { switch (v1) { case TYPE_NONE: case TYPE_STRING: case TYPE_DOUBLE: case TYPE_OBJ: case TYPE_DATE: assert (v1 == v2); break; case TYPE_INT32: case TYPE_UINT32: assert (v2 == TYPE_INT32 || v2 == TYPE_UINT32); break; case TYPE_INT64: case TYPE_UINT64: assert (v2 == TYPE_INT64 || v2 == TYPE_UINT64); break; default: assert (0); } } class DataINT32 : public Data { public: DataINT32 () { data = new Vector; } virtual ~DataINT32 () { delete data; } virtual VType_type type () { return TYPE_INT32; } virtual void reset () { data->reset (); } virtual long getSize () { return data->size (); } virtual int fetchInt (long i) { return (int) data->fetch (i); } virtual unsigned long long fetchULong (long i) { return (unsigned long long) data->fetch (i); } virtual long long fetchLong (long i) { return (long long) data->fetch (i); } virtual char * fetchString (long i) { return dbe_sprintf (NTXT ("%d"), data->fetch (i)); } virtual double fetchDouble (long i) { return (double) data->fetch (i); } virtual void * fetchObject (long) { assert (ASSERT_SKIP); return NULL; } virtual void setDatumValue (long idx, const Datum *val) { data->store (idx, val->i); } virtual void setValue (long idx, uint64_t val) { data->store (idx, (int32_t) val); } virtual void setObjValue (long, void*) { assert (ASSERT_SKIP); return; } virtual int cmpValues (long idx1, long idx2) { int32_t i1 = data->fetch (idx1); int32_t i2 = data->fetch (idx2); return i1 < i2 ? -1 : i1 > i2 ? 1 : 0; } virtual int cmpDatumValue (long idx, const Datum *val) { int32_t i1 = data->fetch (idx); int32_t i2 = val->i; return i1 < i2 ? -1 : i1 > i2 ? 1 : 0; } private: Vector *data; }; class DataUINT32 : public Data { public: DataUINT32 () { data = new Vector; } virtual ~DataUINT32 () { delete data; } virtual VType_type type () { return TYPE_UINT32; } virtual void reset () { data->reset (); } virtual long getSize () { return data->size (); } virtual int fetchInt (long i) { return (int) data->fetch (i); } virtual unsigned long long fetchULong (long i) { return (unsigned long long) data->fetch (i); } virtual long long fetchLong (long i) { return (long long) data->fetch (i); } virtual char * fetchString (long i) { return dbe_sprintf (NTXT ("%u"), data->fetch (i)); } virtual double fetchDouble (long i) { return (double) data->fetch (i); } virtual void * fetchObject (long) { assert (ASSERT_SKIP); return NULL; } virtual void setDatumValue (long idx, const Datum *val) { data->store (idx, val->i); } virtual void setValue (long idx, uint64_t val) { data->store (idx, (uint32_t) val); } virtual void setObjValue (long, void*) { assert (ASSERT_SKIP); return; } virtual int cmpValues (long idx1, long idx2) { uint32_t u1 = data->fetch (idx1); uint32_t u2 = data->fetch (idx2); return u1 < u2 ? -1 : u1 > u2 ? 1 : 0; } virtual int cmpDatumValue (long idx, const Datum *val) { uint32_t u1 = data->fetch (idx); uint32_t u2 = (uint32_t) val->i; return u1 < u2 ? -1 : u1 > u2 ? 1 : 0; } private: Vector *data; }; class DataINT64 : public Data { public: DataINT64 () { data = new Vector; } virtual ~DataINT64 () { delete data; } virtual VType_type type () { return TYPE_INT64; } virtual void reset () { data->reset (); } virtual long getSize () { return data->size (); } virtual int fetchInt (long i) { return (int) data->fetch (i); } virtual unsigned long long fetchULong (long i) { return (unsigned long long) data->fetch (i); } virtual long long fetchLong (long i) { return (long long) data->fetch (i); } virtual char * fetchString (long i) { return dbe_sprintf (NTXT ("%lld"), (long long) data->fetch (i)); } virtual double fetchDouble (long i) { return (double) data->fetch (i); } virtual void * fetchObject (long) { assert (ASSERT_SKIP); return NULL; } virtual void setDatumValue (long idx, const Datum *val) { data->store (idx, val->ll); } virtual void setValue (long idx, uint64_t val) { data->store (idx, (int64_t) val); } virtual void setObjValue (long, void*) { assert (ASSERT_SKIP); return; } virtual int cmpValues (long idx1, long idx2) { int64_t i1 = data->fetch (idx1); int64_t i2 = data->fetch (idx2); return i1 < i2 ? -1 : i1 > i2 ? 1 : 0; } virtual int cmpDatumValue (long idx, const Datum *val) { int64_t i1 = data->fetch (idx); int64_t i2 = val->ll; return i1 < i2 ? -1 : i1 > i2 ? 1 : 0; } private: Vector *data; }; class DataUINT64 : public Data { public: DataUINT64 () { data = new Vector; } virtual ~DataUINT64 () { delete data; } virtual VType_type type () { return TYPE_UINT64; } virtual void reset () { data->reset (); } virtual long getSize () { return data->size (); } virtual int fetchInt (long i) { return (int) data->fetch (i); } virtual unsigned long long fetchULong (long i) { return (unsigned long long) data->fetch (i); } virtual long long fetchLong (long i) { return (long long) data->fetch (i); } virtual char * fetchString (long i) { return dbe_sprintf (NTXT ("%llu"), (long long) data->fetch (i)); } virtual double fetchDouble (long i) { return (double) data->fetch (i); } virtual void * fetchObject (long) { assert (ASSERT_SKIP); return NULL; } virtual void setDatumValue (long idx, const Datum *val) { data->store (idx, val->ll); } virtual void setValue (long idx, uint64_t val) { data->store (idx, val); } virtual void setObjValue (long, void*) { assert (ASSERT_SKIP); return; } virtual int cmpValues (long idx1, long idx2) { uint64_t u1 = data->fetch (idx1); uint64_t u2 = data->fetch (idx2); return u1 < u2 ? -1 : u1 > u2 ? 1 : 0; } virtual int cmpDatumValue (long idx, const Datum *val) { uint64_t u1 = data->fetch (idx); uint64_t u2 = (uint64_t) val->ll; return u1 < u2 ? -1 : u1 > u2 ? 1 : 0; } private: Vector *data; }; class DataOBJECT : public Data { public: DataOBJECT () { dtype = TYPE_OBJ; data = new Vector; } DataOBJECT (VType_type _dtype) { dtype = _dtype; data = new Vector; } virtual ~DataOBJECT () { delete data; } virtual VType_type type () { return dtype; } virtual void reset () { data->reset (); } virtual long getSize () { return data->size (); } virtual int fetchInt (long) { assert (ASSERT_SKIP); return 0; } virtual unsigned long long fetchULong (long) { assert (ASSERT_SKIP); return 0LL; } virtual long long fetchLong (long) { assert (ASSERT_SKIP); return 0LL; } virtual char * fetchString (long i) { return dbe_sprintf (NTXT ("%lu"), (unsigned long) data->fetch (i)); } virtual double fetchDouble (long) { assert (ASSERT_SKIP); return 0.0; } virtual void * fetchObject (long i) { return data->fetch (i); } virtual void setDatumValue (long idx, const Datum *val) { data->store (idx, val->p); } virtual void setValue (long, uint64_t) { assert (ASSERT_SKIP); return; } virtual void setObjValue (long idx, void *p) { data->store (idx, p); } virtual int cmpValues (long, long) { return 0; } virtual int cmpDatumValue (long, const Datum *) { return 0; } private: VType_type dtype; Vector *data; }; class DataSTRING : public Data { public: DataSTRING () { data = new Vector; } virtual ~DataSTRING () { data->destroy (); delete data; } virtual VType_type type () { return TYPE_STRING; } virtual void reset () { data->reset (); } virtual long getSize () { return data->size (); } virtual int fetchInt (long) { return 0; } virtual unsigned long long fetchULong (long) { return 0LL; } virtual long long fetchLong (long) { return 0LL; } virtual char * fetchString (long i) { return xstrdup (data->fetch (i)); } virtual double fetchDouble (long) { return 0.0; } virtual void * fetchObject (long i) { return data->fetch (i); } virtual void setDatumValue (long idx, const Datum *val) { data->store (idx, val->l); } virtual void setValue (long, uint64_t) { return; } virtual void setObjValue (long idx, void *p) { data->store (idx, (char*) p); } virtual int cmpValues (long, long) { return 0; } virtual int cmpDatumValue (long, const Datum *) { return 0; } private: Vector *data; }; class DataDOUBLE : public Data { public: DataDOUBLE () { data = new Vector; } virtual ~DataDOUBLE () { delete data; } virtual VType_type type () { return TYPE_DOUBLE; } virtual void reset () { data->reset (); } virtual long getSize () { return data->size (); } virtual int fetchInt (long i) { return (int) data->fetch (i); } virtual unsigned long long fetchULong (long i) { return (unsigned long long) data->fetch (i); } virtual long long fetchLong (long i) { return (long long) data->fetch (i); } virtual char * fetchString (long i) { return dbe_sprintf (NTXT ("%f"), data->fetch (i)); } virtual double fetchDouble (long i) { return data->fetch (i); } virtual void setDatumValue (long idx, const Datum *val) { data->store (idx, val->d); } virtual void setValue (long idx, uint64_t val) { data->store (idx, (double) val); } virtual void setObjValue (long, void*) { return; } virtual void * fetchObject (long) { return NULL; } virtual int cmpValues (long idx1, long idx2) { double d1 = data->fetch (idx1); double d2 = data->fetch (idx2); return d1 < d2 ? -1 : d1 > d2 ? 1 : 0; } virtual int cmpDatumValue (long idx, const Datum *val) { double d1 = data->fetch (idx); double d2 = val->d; return d1 < d2 ? -1 : d1 > d2 ? 1 : 0; } private: Vector *data; }; Data * Data::newData (VType_type vtype) { switch (vtype) { case TYPE_INT32: return new DataINT32; case TYPE_UINT32: return new DataUINT32; case TYPE_INT64: return new DataINT64; case TYPE_UINT64: return new DataUINT64; case TYPE_OBJ: return new DataOBJECT; case TYPE_STRING: return new DataSTRING; case TYPE_DOUBLE: return new DataDOUBLE; default: return NULL; } } /* * class DataDescriptor */ DataDescriptor::DataDescriptor (int _id, const char *_name, const char *_uname, int _flags) { isMaster = true; id = _id; name = _name ? xstrdup (_name) : xstrdup (NTXT ("")); uname = _uname ? xstrdup (_uname) : xstrdup (NTXT ("")); flags = _flags; // master data, shared with reference copies: master_size = 0; master_resolveFrameInfoDone = false; props = new Vector; data = new Vector; setsTBR = new Vector*>; // master references point to self: ref_size = &master_size; ref_resolveFrameInfoDone = &master_resolveFrameInfoDone; } DataDescriptor::DataDescriptor (int _id, const char *_name, const char *_uname, DataDescriptor* dDscr) { isMaster = false; id = _id; name = _name ? xstrdup (_name) : xstrdup (NTXT ("")); uname = _uname ? xstrdup (_uname) : xstrdup (NTXT ("")); flags = dDscr->flags; // references point to master DataDescriptor ref_size = &dDscr->master_size; ref_resolveFrameInfoDone = &dDscr->master_resolveFrameInfoDone; props = dDscr->props; data = dDscr->data; setsTBR = dDscr->setsTBR; // data that should never be accessed in reference copy master_size = -1; master_resolveFrameInfoDone = false; } DataDescriptor::~DataDescriptor () { free (name); free (uname); if (!isMaster) return; props->destroy (); delete props; data->destroy (); delete data; setsTBR->destroy (); delete setsTBR; } void DataDescriptor::reset () { if (!isMaster) return; for (int i = 0; i < data->size (); i++) { Data *d = data->fetch (i); if (d != NULL) d->reset (); Vector *set = setsTBR->fetch (i); if (set != NULL) set->reset (); } master_size = 0; } PropDescr * DataDescriptor::getProp (int prop_id) { for (int i = 0; i < props->size (); i++) { PropDescr *propDscr = props->fetch (i); if (propDscr->propID == prop_id) return propDscr; } return NULL; } Data * DataDescriptor::getData (int prop_id) { if (prop_id < 0 || prop_id >= data->size ()) return NULL; return data->fetch (prop_id); } void DataDescriptor::addProperty (PropDescr *propDscr) { if (propDscr == NULL) return; if (propDscr->propID < 0) return; PropDescr *oldProp = getProp (propDscr->propID); if (oldProp != NULL) { checkCompatibility (propDscr->vtype, oldProp->vtype); //YXXX depends on experiment correctness delete propDscr; return; } props->append (propDscr); data->store (propDscr->propID, Data::newData (propDscr->vtype)); setsTBR->store (propDscr->propID, NULL); } long DataDescriptor::addRecord () { if (!isMaster) return -1; return master_size++; } static void checkEntity (Vector *set, long long val) { // Binary search int lo = 0; int hi = set->size () - 1; while (lo <= hi) { int md = (lo + hi) / 2; long long ent = set->fetch (md); if (ent < val) lo = md + 1; else if (ent > val) hi = md - 1; else return; } set->insert (lo, val); } void DataDescriptor::setDatumValue (int prop_id, long idx, const Datum *val) { if (idx >= *ref_size) return; Data *d = getData (prop_id); if (d != NULL) { VType_type datum_type = val->type; VType_type data_type = d->type (); checkCompatibility (datum_type, data_type); d->setDatumValue (idx, val); Vector *set = setsTBR->fetch (prop_id); if (set != NULL)// Sets are maintained checkEntity (set, d->fetchLong (idx)); } } void DataDescriptor::setValue (int prop_id, long idx, uint64_t val) { if (idx >= *ref_size) return; Data *d = getData (prop_id); if (d != NULL) { d->setValue (idx, val); Vector *set = setsTBR->fetch (prop_id); if (set != NULL)// Sets are maintained checkEntity (set, d->fetchLong (idx)); } } void DataDescriptor::setObjValue (int prop_id, long idx, void *val) { if (idx >= *ref_size) return; Data *d = getData (prop_id); if (d != NULL) d->setObjValue (idx, val); } DataView * DataDescriptor::createView () { return new DataView (this); } DataView * DataDescriptor::createImmutableView () { return new DataView (this, DataView::DV_IMMUTABLE); } DataView * DataDescriptor::createExtManagedView () { return new DataView (this, DataView::DV_EXT_MANAGED); } int DataDescriptor::getIntValue (int prop_id, long idx) { Data *d = getData (prop_id); if (d == NULL || idx >= d->getSize ()) return 0; return d->fetchInt (idx); } unsigned long long DataDescriptor::getULongValue (int prop_id, long idx) { Data *d = getData (prop_id); if (d == NULL || idx >= d->getSize ()) return 0L; return d->fetchULong (idx); } long long DataDescriptor::getLongValue (int prop_id, long idx) { Data *d = getData (prop_id); if (d == NULL || idx >= d->getSize ()) return 0L; return d->fetchLong (idx); } void * DataDescriptor::getObjValue (int prop_id, long idx) { Data *d = getData (prop_id); if (d == NULL || idx >= d->getSize ()) return NULL; return d->fetchObject (idx); } static int pcmp (const void *p1, const void *p2, const void *arg) { long idx1 = *(long*) p1; // index1 into Data long idx2 = *(long*) p2; // index2 into Data for (Data **dsorted = (Data**) arg; *dsorted != DATA_SORT_EOL; dsorted++) { Data *data = *dsorted; if (data == NULL)// sort property not in this data, skip this criteria continue; int res = data->cmpValues (idx1, idx2); if (res) return res; } // Provide stable sort return idx1 < idx2 ? -1 : idx1 > idx2 ? 1 : 0; } Vector * DataDescriptor::getSet (int prop_id) { if (prop_id < 0 || prop_id >= setsTBR->size ()) return NULL; Vector *set = setsTBR->fetch (prop_id); if (set != NULL) return set; Data *d = getData (prop_id); if (d == NULL) return NULL; set = new Vector; for (long i = 0; i<*ref_size; ++i) checkEntity (set, d->fetchLong (i)); setsTBR->store (prop_id, set); return set; } /* * class DataView */ DataView::DataView (DataDescriptor *_ddscr) { init (_ddscr, DV_NORMAL); } DataView::DataView (DataDescriptor *_ddscr, DataViewType _type) { init (_ddscr, _type); } void DataView::init (DataDescriptor *_ddscr, DataViewType _type) { ddscr = _ddscr; type = _type; switch (type) { case DV_IMMUTABLE: ddsize = ddscr->getSize (); index = NULL; break; case DV_NORMAL: case DV_EXT_MANAGED: ddsize = 0; index = new Vector; break; } for (int ii = 0; ii < (MAX_SORT_DIMENSIONS + 1); ii++) sortedBy[ii] = DATA_SORT_EOL; filter = NULL; } DataView::~DataView () { delete filter; delete index; } void DataView::appendDataDescriptorId (long pkt_id /* ddscr index */) { if (type != DV_EXT_MANAGED) return; // updates allowed only on externally managed DataViews long curr_ddsize = ddscr->getSize (); if (pkt_id < 0 || pkt_id >= curr_ddsize) return; // error! index->append (pkt_id); } void DataView::setDataDescriptorValue (int prop_id, long pkt_id, uint64_t val) { ddscr->setValue (prop_id, pkt_id, val); } long long DataView::getDataDescriptorValue (int prop_id, long pkt_id) { return ddscr->getLongValue (prop_id, pkt_id); } Vector* DataView::getProps () { return ddscr->getProps (); }; PropDescr* DataView::getProp (int prop_id) { return ddscr->getProp (prop_id); }; void DataView::filter_in_chunks (fltr_dbe_ctx *dctx) { Expression::Context *e_ctx = new Expression::Context (dctx->fltr->ctx->dbev, dctx->fltr->ctx->exp); Expression *n_expr = dctx->fltr->expr->copy (); bool noParFilter = dctx->fltr->noParFilter; FilterExp *nFilter = new FilterExp (n_expr, e_ctx, noParFilter); long iter = dctx->begin; long end = dctx->end; long orig_ddsize = dctx->orig_ddsize; while (iter < end) { nFilter->put (dctx->tmpView, iter); if (nFilter->passes ()) dctx->idxArr[iter - orig_ddsize] = 1; iter += 1; } delete nFilter; } bool DataView::checkUpdate () { long newSize = ddscr->getSize (); if (ddsize == newSize) return false; if (index == NULL) return false; if (type == DV_EXT_MANAGED) return false; bool updated = false; if (filter) { DataView *tmpView = ddscr->createImmutableView (); assert (tmpView->getSize () == newSize); while (ddsize < newSize) { filter->put (tmpView, ddsize); if (filter->passes ()) index->append (ddsize); ddsize += 1; } delete tmpView; return updated; } while (ddsize < newSize) { index->append (ddsize); updated = true; ddsize += 1; } return updated; } long DataView::getSize () { if (checkUpdate () && sortedBy[0] != DATA_SORT_EOL) // note: after new filter is set, getSize() incurs cost of // sorting even if caller isn't interested in sort index->sort ((CompareFunc) pcmp, sortedBy); if (index == NULL) return ddscr->getSize (); return index->size (); } void DataView::setDatumValue (int prop_id, long idx, const Datum *val) { ddscr->setDatumValue (prop_id, getIdByIdx (idx), val); } void DataView::setValue (int prop_id, long idx, uint64_t val) { ddscr->setValue (prop_id, getIdByIdx (idx), val); } void DataView::setObjValue (int prop_id, long idx, void *val) { ddscr->setObjValue (prop_id, getIdByIdx (idx), val); } int DataView::getIntValue (int prop_id, long idx) { return ddscr->getIntValue (prop_id, getIdByIdx (idx)); } unsigned long long DataView::getULongValue (int prop_id, long idx) { return ddscr->getULongValue (prop_id, getIdByIdx (idx)); } long long DataView::getLongValue (int prop_id, long idx) { return ddscr->getLongValue (prop_id, getIdByIdx (idx)); } void * DataView::getObjValue (int prop_id, long idx) { return ddscr->getObjValue (prop_id, getIdByIdx (idx)); } void DataView::sort (const int props[], int prop_count) { if (index == NULL) { assert (ASSERT_SKIP); return; } assert (prop_count >= 0 && prop_count < MAX_SORT_DIMENSIONS); bool sort_changed = false; // see if sort has changed... for (int ii = 0; ii <= prop_count; ii++) { // sortedBy size is prop_count+1 Data *data; if (ii == prop_count) data = DATA_SORT_EOL; // special end of array marker else data = ddscr->getData (props[ii]); if (sortedBy[ii] != data) { sortedBy[ii] = data; sort_changed = true; } } if (!checkUpdate () && !sort_changed) return; index->sort ((CompareFunc) pcmp, sortedBy); } void DataView::sort (int prop0) { sort (&prop0, 1); } void DataView::sort (int prop0, int prop1) { int props[2] = {prop0, prop1}; sort (props, 2); } void DataView::sort (int prop0, int prop1, int prop2) { int props[3] = {prop0, prop1, prop2}; sort (props, 3); } void DataView::setFilter (FilterExp *f) { if (index == NULL) { assert (ASSERT_SKIP); return; } delete filter; filter = f; index->reset (); ddsize = 0; checkUpdate (); } long DataView::getIdByIdx (long idx) { if (index == NULL) return idx; return index->fetch (idx); } static int tvalcmp (long data_id, const Datum valColumns[], Data *sortedBy[]) { for (int ii = 0; ii < MAX_SORT_DIMENSIONS; ii++) { if (sortedBy[ii] == DATA_SORT_EOL) break; Data *d = sortedBy[ii]; if (d == NULL)// property doesn't exist in data; compare always matches continue; const Datum *tvalue = &valColumns[ii]; int res = d->cmpDatumValue (data_id, tvalue); if (res) return res; } return 0; } static void checkSortTypes (const Datum valColumns[], Data *sortedBy[]) { #ifndef NDEBUG for (int ii = 0; ii < MAX_SORT_DIMENSIONS; ii++) { if (sortedBy[ii] == DATA_SORT_EOL) break; Data *d = sortedBy[ii]; if (d == NULL)// property doesn't exist in data; compare always matches continue; VType_type datum_type = valColumns[ii].type; VType_type data_type = d->type (); checkCompatibility (datum_type, data_type); } #endif } bool DataView::idxRootDimensionsMatch (long idx, const Datum valColumns[]) { // compares idx vs. valColumns[] - If all dimensions match // (except sort leaf), then the leaf value is valid => return true. // Otherwise, return false. checkSortTypes (valColumns, sortedBy); if (idx < 0 || idx >= index->size ()) // fell off end of array return false; long data_id = index->fetch (idx); // we will check all dimensions for a match except the "leaf" dimension for (int ii = 0; ii < (MAX_SORT_DIMENSIONS - 1); ii++) { if (sortedBy[ii + 1] == DATA_SORT_EOL) break; // we are at leaf dimension, don't care about it's value if (sortedBy[ii] == DATA_SORT_EOL) break; // end of list Data *d = sortedBy[ii]; if (d == NULL) // property doesn't exist in data; compare always matches continue; const Datum *tvalue = &valColumns[ii]; int res = d->cmpDatumValue (data_id, tvalue); if (res) return false; } return true; } long DataView::getIdxByVals (const Datum valColumns[], Relation rel) { // checks sortedBy[] columns for match; relation only used on last column return getIdxByVals (valColumns, rel, -1, -1); } long DataView::getIdxByVals (const Datum valColumns[], Relation rel, long minIdx, long maxIdx) { // checks sortedBy[] columns for match; relation only used on last column checkSortTypes (valColumns, sortedBy); if (index == NULL || sortedBy[0] == DATA_SORT_EOL) return -1; long lo; if (minIdx < 0) lo = 0; else lo = minIdx; long hi; if (maxIdx < 0 || maxIdx >= index->size ()) hi = index->size () - 1; else hi = maxIdx; long md = -1; while (lo <= hi) { md = (lo + hi) / 2; int cmp = tvalcmp (index->fetch (md), valColumns, sortedBy); if (cmp < 0) { lo = md + 1; continue; } else if (cmp > 0) { hi = md - 1; continue; } // cmp == 0, we have an exact match switch (rel) { case REL_LT: hi = md - 1; // continue searching break; case REL_GT: lo = md + 1; // continue searching break; case REL_LTEQ: case REL_GTEQ: case REL_EQ: // note: "md" may not be deterministic if multiple matches exist return md; // a match => done. } } // no exact match found switch (rel) { case REL_LT: case REL_LTEQ: md = hi; break; case REL_GT: case REL_GTEQ: md = lo; break; case REL_EQ: return -1; } if (idxRootDimensionsMatch (md, valColumns)) return md; return -1; } void DataView::removeDbeViewIdx (long idx) { index->remove (idx); }