int calc_blob_column(const NdbDictionary::Table * t, const NdbDictionary::Index * ix, int col, Ndb* ndb, int & szRam, int & szDisk, bool ftScan) { NdbTransaction * trans = ndb->startTransaction(); NdbScanOperation * sop = trans->getNdbScanOperation(t); sop->readTuples(); NdbBlob * blob = sop->getBlobHandle(col); bool no_data=false; if(trans->execute(NdbTransaction::NoCommit, NdbOperation::AbortOnError, 1) == -1) { no_data=true; sop->close(); trans->close(); } unsigned long long len=0; int rows=0; int check=0; const NdbDictionary::Column * c = t->getColumn(col); int part_size= c->getPartSize(); if(!no_data) { while(((check = sop->nextResult(true)) == 0) && !ignoreData) { int isnull; rows++; blob->getNull(isnull); if(isnull) len=0; else blob->getLength(len); /* printf("blob is %llu\n", len); if(len>256) { szRam+=(((len-256)/part_size) + 1)*part_size+256; printf("len2=%llu, part-size=%d, len=%llu\n", (((len-256)/part_size) + 1)*part_size+256, part_size, len); } else */ szRam+=(int)len; if(rows==1000 && !ftScan) break; } sop->close(); trans->close(); } if(rows==0) { if (c->getStorageType() == NdbDictionary::Column::StorageTypeDisk) { printf("---\tWARNING! No reference data found for BLOB/TEXT. " "Defaulting to 256 bytes DataMemory, %d bytes Diskspace! \n",(part_size<=256 ? 0:part_size)); printf("\tConsider loading database with average data for exact" " measurement. \n"); szRam=256; szDisk=(part_size<=256 ? 0:part_size); return 0; } else { printf("---\tWARNING! No reference data found for BLOB/TEXT. " "Defaulting to %d bytes DataMemory ! \n", (part_size<=256 ? 256:part_size+256)); printf("\tConsider loading database with average data for exact" " measurement. \n"); szRam=(part_size<=256 ? 256:part_size+256); szDisk=0; return 0; } } if (c->getStorageType() == NdbDictionary::Column::StorageTypeDisk) { int averageSz=szRam/rows; if((averageSz)>256) { szRam=256; szDisk=((averageSz-256)/part_size) *part_size + (((averageSz-256)%part_size)==0 ? 0:part_size); } else { szRam=256; szDisk=0; } } else { int averageSz=szRam/rows; szDisk=0; if((averageSz)<256) { szRam=256; } else { szRam=256 + ((averageSz-256)/part_size)*part_size + (((averageSz-256)%part_size)==0 ? 0:part_size); } } printf("---\tBLOB/TEXT attribute is %d bytes (RAM) and %d bytes (DISK)" " averaged over %d rows\n", szRam, szDisk, rows); return 0; }
int main(int argc, char** argv) { if (argc < 3) { std::cout << "Arguments are <connect_string cluster> <timeout> [m(merge events)|d(debug)].\n"; exit(-1); } const char *connectstring = argv[1]; int timeout = atoi(argv[2]); ndb_init(); bool merge_events = argc > 3 && strchr(argv[3], 'm') != 0; #ifdef VM_TRACE bool dbug = argc > 3 && strchr(argv[3], 'd') != 0; if (dbug) DBUG_PUSH("d:t:"); if (dbug) putenv("API_SIGNAL_LOG=-"); #endif Ndb_cluster_connection *cluster_connection= new Ndb_cluster_connection(connectstring); // Object representing the cluster int r= cluster_connection->connect(5 /* retries */, 3 /* delay between retries */, 1 /* verbose */); if (r > 0) { std::cout << "Cluster connect failed, possibly resolved with more retries.\n"; exit(-1); } else if (r < 0) { std::cout << "Cluster connect failed.\n"; exit(-1); } if (cluster_connection->wait_until_ready(30,30)) { std::cout << "Cluster was not ready within 30 secs." << std::endl; exit(-1); } Ndb* myNdb= new Ndb(cluster_connection, "TEST_DB"); // Object representing the database if (myNdb->init() == -1) APIERROR(myNdb->getNdbError()); const char *eventName= "CHNG_IN_t0"; const char *eventTableName= "t0"; const int noEventColumnName= 5; const char *eventColumnName[noEventColumnName]= {"c0", "c1", "c2", "c3", "c4" }; // Create events myCreateEvent(myNdb, eventName, eventTableName, eventColumnName, noEventColumnName, merge_events); // Normal values and blobs are unfortunately handled differently.. typedef union { NdbRecAttr* ra; NdbBlob* bh; } RA_BH; int i, j, k, l; j = 0; while (j < timeout) { // Start "transaction" for handling events NdbEventOperation* op; printf("create EventOperation\n"); if ((op = myNdb->createEventOperation(eventName)) == NULL) APIERROR(myNdb->getNdbError()); op->mergeEvents(merge_events); printf("get values\n"); RA_BH recAttr[noEventColumnName]; RA_BH recAttrPre[noEventColumnName]; // primary keys should always be a part of the result for (i = 0; i < noEventColumnName; i++) { if (i < 4) { recAttr[i].ra = op->getValue(eventColumnName[i]); recAttrPre[i].ra = op->getPreValue(eventColumnName[i]); } else if (merge_events) { recAttr[i].bh = op->getBlobHandle(eventColumnName[i]); recAttrPre[i].bh = op->getPreBlobHandle(eventColumnName[i]); } } // set up the callbacks printf("execute\n"); // This starts changes to "start flowing" if (op->execute()) APIERROR(op->getNdbError()); NdbEventOperation* the_op = op; i= 0; while (i < timeout) { // printf("now waiting for event...\n"); int r = myNdb->pollEvents(1000); // wait for event or 1000 ms if (r > 0) { // printf("got data! %d\n", r); while ((op= myNdb->nextEvent())) { assert(the_op == op); i++; switch (op->getEventType()) { case NdbDictionary::Event::TE_INSERT: printf("%u INSERT", i); break; case NdbDictionary::Event::TE_DELETE: printf("%u DELETE", i); break; case NdbDictionary::Event::TE_UPDATE: printf("%u UPDATE", i); break; default: abort(); // should not happen } printf(" gci=%d\n", (int)op->getGCI()); for (k = 0; k <= 1; k++) { printf(k == 0 ? "post: " : "pre : "); for (l = 0; l < noEventColumnName; l++) { if (l < 4) { NdbRecAttr* ra = k == 0 ? recAttr[l].ra : recAttrPre[l].ra; if (ra->isNULL() >= 0) { // we have a value if (ra->isNULL() == 0) { // we have a non-null value if (l < 2) printf("%-5u", ra->u_32_value()); else printf("%-5.4s", ra->aRef()); } else printf("%-5s", "NULL"); } else printf("%-5s", "-"); // no value } else if (merge_events) { int isNull; NdbBlob* bh = k == 0 ? recAttr[l].bh : recAttrPre[l].bh; bh->getDefined(isNull); if (isNull >= 0) { // we have a value if (! isNull) { // we have a non-null value Uint64 length = 0; bh->getLength(length); // read into buffer unsigned char* buf = new unsigned char [length]; memset(buf, 'X', length); Uint32 n = length; bh->readData(buf, n); // n is in/out assert(n == length); // pretty-print bool first = true; Uint32 i = 0; while (i < n) { unsigned char c = buf[i++]; Uint32 m = 1; while (i < n && buf[i] == c) i++, m++; if (! first) printf("+"); printf("%u%c", m, c); first = false; } printf("[%u]", n); delete [] buf; } else printf("%-5s", "NULL"); } else printf("%-5s", "-"); // no value } } printf("\n"); } } } else printf("timed out (%i)\n", timeout); } // don't want to listen to events anymore if (myNdb->dropEventOperation(the_op)) APIERROR(myNdb->getNdbError()); the_op = 0; j++; } { NdbDictionary::Dictionary *myDict = myNdb->getDictionary(); if (!myDict) APIERROR(myNdb->getNdbError()); // remove event from database if (myDict->dropEvent(eventName)) APIERROR(myDict->getNdbError()); } delete myNdb; delete cluster_connection; ndb_end(0); return 0; }