/** * 随机构造总大小为dataSize的记录插入到table中, * 记录ID从在[minidx, minid]之间随机生成 * @param table 数据表 * @param dataSize 记录总大小 * @param maxid 最大id * @param minid 最小id * @return 记录数 */ uint TNTCountTable::populate(Session *session, TNTTable *table, TNTOpInfo *opInfo, u64 *dataSize, u64 maxId, u64 minId) { assert(session->getTrans() != NULL); u64 volumnCnt = *dataSize; uint recCnt = 0; uint dupIdx; int startId = 0; Record *rec; RowId rid; while (true) { // 创建记录 u64 id = (u64)RandomGen::nextInt((u32)minId, (u32)maxId); rec = createRecord((u64)recCnt, (int)startId++); if (volumnCnt < getRecordSize()) { freeRecord(rec); break; } // 插入记录 rid = table->insert(session, rec->m_data, &dupIdx, opInfo); if (rid != INVALID_ROW_ID) { recCnt++; volumnCnt -= getRecordSize(); } freeRecord(rec); } *dataSize -= volumnCnt; return recCnt; }
RC updateRecord(RM_TableData *rel, Record *record) { RID *rid = &record->id; RM_TableMgmtData *tableMgmtData = rel->mgmtData; RM_Page *page; // Check to see if feasible record if (rid->page == NO_PAGE || rid->slot == NO_SLOT) { return RC_RM_NO_RECORD; } RC pinPageResult; if (pinPageResult = pinPage(&tableMgmtData->bufferPool, &tableMgmtData->pageHandle, rid->page) != RC_OK) { return pinPageResult; } page = (RM_Page*)tableMgmtData->pageHandle.data; char *slotOffset = ((char*)&page->data) + (rid->slot * getRecordSize(rel->schema)); int recordSize = getRecordSize(rel->schema); memcpy(slotOffset + 1, record->data, recordSize); RC markDirtyResult; if (markDirtyResult = markDirty(&tableMgmtData->bufferPool, &tableMgmtData->pageHandle) != RC_OK) { return markDirtyResult; } RC unpinPageResult; if (unpinPageResult = unpinPage(&tableMgmtData->bufferPool, &tableMgmtData->pageHandle) != RC_OK) { return unpinPageResult; } return RC_OK; }
int findFreeSlot(RM_Page *page, Schema *schema) { int totalSlots = ((int)(PAGE_SIZE - ((&((RM_Page*)0)->data) - ((char*)0)))) / getRecordSize(schema); char *slotOffset = (char*)&page->data; int recordSize = getRecordSize(schema); int slot; for (slot = 0; slot < totalSlots; slot++) { // Do we have a tombstone? if ((*(char*)slotOffset) <= 0) { return slot; } slotOffset = slotOffset + recordSize; } return NO_SLOT; }
// Simply marks tombstones, doesn't physically delete or allow for records to overwrite RC deleteRecord(RM_TableData *rel, RID id) { RM_TableMgmtData *tableMgmtData = rel->mgmtData; RM_Page *page; RC pinPageResult; if (pinPageResult = pinPage(&tableMgmtData->bufferPool, &tableMgmtData->pageHandle, id.page) != RC_OK) { return pinPageResult; } page = (RM_Page*)tableMgmtData->pageHandle.data; char *slotOffset = ((char*)&page->data) + (id.slot*getRecordSize(rel->schema)); // Update tombstone *(char*)slotOffset = -1; RC markDirtyResult; if (markDirtyResult = markDirty(&tableMgmtData->bufferPool, &tableMgmtData->pageHandle) != RC_OK) { return markDirtyResult; } RC unpinPageResult; if (unpinPageResult = unpinPage(&tableMgmtData->bufferPool, &tableMgmtData->pageHandle) != RC_OK) { return unpinPageResult; } tableMgmtData->numTuples--; return RC_OK; }
/* * Creates a new Record and allocates memmory for record & its data */ RC createRecord (Record **record, Schema *schema) { *record = (Record*)malloc(sizeof(Record)); (*record)->data = (char*)malloc(getRecordSize(schema)); return RC_OK; }
/** * Creates and returns the record handle to be used by client * * record = record handle to be initialized * schema = schema on which record is to be based */ RC createRecord(Record **record, Schema *schema) { //Sanity Checks if (schema == NULL) { THROW(RC_INVALID_HANDLE, "Schema handle is invalid"); } *record = (Record *) malloc(sizeof(Record)); if (record == NULL) { THROW(RC_NOT_ENOUGH_MEMORY, "Not enough memory available for resource allocation"); } int recordLen = getRecordSize(schema); //Reset the NULL map (*record)->nullMap = 0x0000; (*record)->data = (char*) malloc(recordLen); memset((*record)->data, '\0', recordLen); if ((*record)->data == NULL) { THROW(RC_NOT_ENOUGH_MEMORY, "Not enough memory available for resource allocation"); } //All OK return RC_OK; }
/** Implementation of scanner.h **/ void update(int pageno,Schema *sch,TableManager *tableManager, Pager *dp){ int i; int slotId =-1; int _rSize= getRecordSize(sch)+1; char *slotAddr= ((char*) &dp->data); int totalSlots= ( ((int)(PAGE_SIZE - ((&((Pager*)0)->data) - ((char*)0)) )/(getRecordSize(sch)+1) )); for (i=0; i<totalSlots; i++){ if (!(*(char*)slotAddr)>0){ slotId = i; break; } slotAddr= _rSize+slotAddr; } if (slotId <= 0){ pop(tableManager, dp, pageno);} else{ push(tableManager, dp, pageno); } }
RC getRecord(RM_TableData *rel, RID id, Record *record) { RM_TableMgmtData *tableMgmtData = rel->mgmtData; RM_Page *page; if (id.page == NO_PAGE || id.slot == NO_SLOT) { return RC_RM_NO_RECORD; } RC pinPageResult; if (pinPageResult = pinPage(&tableMgmtData->bufferPool, &tableMgmtData->pageHandle, id.page) != RC_OK) { return pinPageResult; } page = (RM_Page *)tableMgmtData->pageHandle.data; char *slotOffset = ((char*)&page->data) + (id.slot * getRecordSize(rel->schema)); memcpy(record->data, slotOffset + 1, getRecordSize(rel->schema) - 1); RC unpinPageResult; if (unpinPageResult = unpinPage(&tableMgmtData->bufferPool, &tableMgmtData->pageHandle) != RC_OK) { return unpinPageResult; } return RC_OK; }
// Khush started working on this // dealing with records and attribute values RC createRecord(Record **record, Schema *schema) { int recordSize; Record *newRecord; // Assign default record values newRecord = MAKE_RECORD(); recordSize = getRecordSize(schema); newRecord->data = MAKE_RECDATA(recordSize); memset(newRecord->data, 0, recordSize); newRecord->id.page = NO_PAGE; newRecord->id.slot = NO_SLOT; // Save record to pointer *record = newRecord; return RC_OK; }
/** * Fetch next matching record satisfying condition expression * * scan = scan handle * record = next matching record returned */ RC next(RM_ScanHandle *scan, Record *record) { RM_ScanIterator* iter = (RM_ScanIterator*) scan->mgmtData; Record* r = iter->records[iter->lastRecordRead + 1]; if ((iter->lastRecordRead + 1) < iter->totalRecords && r != NULL) { record->id.page = r->id.page; record->id.slot = r->id.slot; record->nullMap = r->nullMap; memcpy(record->data, r->data, getRecordSize(scan->rel->schema)); iter->lastRecordRead++; return RC_OK; } return RC_RM_NO_MORE_TUPLES; }
void testScansTwo (void) { RM_TableData *table = (RM_TableData *) malloc(sizeof(RM_TableData)); TestRecord inserts[] = { {1, "aaaa", 3}, {2, "bbbb", 2}, {3, "cccc", 1}, {4, "dddd", 3}, {5, "eeee", 5}, {6, "ffff", 1}, {7, "gggg", 3}, {8, "hhhh", 3}, {9, "iiii", 2}, {10, "jjjj", 5}, }; bool foundScan[] = { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }; int numInserts = 10, i; Record *r; RID *rids; Schema *schema; RM_ScanHandle *sc = (RM_ScanHandle *) malloc(sizeof(RM_ScanHandle)); Expr *sel, *left, *right, *first, *se; int rc; testName = "test creating a new table and inserting tuples"; schema = testSchema(); rids = (RID *) malloc(sizeof(RID) * numInserts); TEST_CHECK(initRecordManager(NULL)); TEST_CHECK(createTable("test_table_r",schema)); TEST_CHECK(openTable(table, "test_table_r")); // insert rows into table for(i = 0; i < numInserts; i++) { r = fromTestRecord(schema, inserts[i]); TEST_CHECK(insertRecord(table,r)); rids[i] = r->id; } TEST_CHECK(closeTable(table)); TEST_CHECK(openTable(table, "test_table_r")); // Select 1 record with INT in condition a=2. MAKE_CONS(left, stringToValue("i2")); MAKE_ATTRREF(right, 0); MAKE_BINOP_EXPR(sel, left, right, OP_COMP_EQUAL); createRecord(&r, schema); TEST_CHECK(startScan(table, sc, sel)); while((rc = next(sc, r)) == RC_OK) { ASSERT_EQUALS_RECORDS(fromTestRecord(schema, inserts[1]), r, schema, "compare records"); } if (rc != RC_NO_TUPLES) TEST_CHECK(rc); TEST_CHECK(closeScan(sc)); // Select 1 record with STRING in condition b='ffff'. MAKE_CONS(left, stringToValue("sffff")); MAKE_ATTRREF(right, 1); MAKE_BINOP_EXPR(sel, left, right, OP_COMP_EQUAL); createRecord(&r, schema); TEST_CHECK(startScan(table, sc, sel)); while((rc = next(sc, r)) == RC_OK) { ASSERT_EQUALS_RECORDS(fromTestRecord(schema, inserts[5]), r, schema, "compare records"); serializeRecord(r, schema); } if (rc != RC_NO_TUPLES) TEST_CHECK(rc); TEST_CHECK(closeScan(sc)); // Select all records, with condition being false MAKE_CONS(left, stringToValue("i4")); MAKE_ATTRREF(right, 2); MAKE_BINOP_EXPR(first, right, left, OP_COMP_SMALLER); MAKE_UNOP_EXPR(se, first, OP_BOOL_NOT); TEST_CHECK(startScan(table, sc, se)); while((rc = next(sc, r)) == RC_OK) { serializeRecord(r, schema); for(i = 0; i < numInserts; i++) { if (memcmp(fromTestRecord(schema, inserts[i])->data,r->data,getRecordSize(schema)) == 0) foundScan[i] = TRUE; } } if (rc != RC_NO_TUPLES) TEST_CHECK(rc); TEST_CHECK(closeScan(sc)); ASSERT_TRUE(!foundScan[0], "not greater than four"); ASSERT_TRUE(foundScan[4], "greater than four"); ASSERT_TRUE(foundScan[9], "greater than four"); // clean up TEST_CHECK(closeTable(table)); TEST_CHECK(deleteTable("test_table_r")); TEST_CHECK(shutdownRecordManager()); freeRecord(r); free(table); free(sc); freeExpr(sel); TEST_DONE(); }
void testScans (void) { RM_TableData *table = (RM_TableData *) malloc(sizeof(RM_TableData)); TestRecord inserts[] = { {1, "aaaa", 3}, {2, "bbbb", 2}, {3, "cccc", 1}, {4, "dddd", 3}, {5, "eeee", 5}, {6, "ffff", 1}, {7, "gggg", 3}, {8, "hhhh", 3}, {9, "iiii", 2}, {10, "jjjj", 5}, }; TestRecord scanOneResult[] = { {3, "cccc", 1}, {6, "ffff", 1}, }; bool foundScan[] = { FALSE, FALSE }; int numInserts = 10, scanSizeOne = 2, i; Record *r; RID *rids; Schema *schema; RM_ScanHandle *sc = (RM_ScanHandle *) malloc(sizeof(RM_ScanHandle)); Expr *sel, *left, *right; int rc; testName = "test creating a new table and inserting tuples"; schema = testSchema(); rids = (RID *) malloc(sizeof(RID) * numInserts); TEST_CHECK(initRecordManager(NULL)); TEST_CHECK(createTable("test_table_r",schema)); TEST_CHECK(openTable(table, "test_table_r")); // insert rows into table for(i = 0; i < numInserts; i++) { r = fromTestRecord(schema, inserts[i]); TEST_CHECK(insertRecord(table,r)); rids[i] = r->id; } TEST_CHECK(closeTable(table)); TEST_CHECK(openTable(table, "test_table_r")); // run some scans MAKE_CONS(left, stringToValue("i1")); MAKE_ATTRREF(right, 2); MAKE_BINOP_EXPR(sel, left, right, OP_COMP_EQUAL); TEST_CHECK(startScan(table, sc, sel)); while((rc = next(sc, r)) == RC_OK) { for(i = 0; i < scanSizeOne; i++) { if (memcmp(fromTestRecord(schema, scanOneResult[i])->data,r->data,getRecordSize(schema)) == 0) foundScan[i] = TRUE; } } if (rc != RC_NO_TUPLES) TEST_CHECK(rc); TEST_CHECK(closeScan(sc)); for(i = 0; i < scanSizeOne; i++) ASSERT_TRUE(foundScan[i], "check for scan result"); // clean up TEST_CHECK(closeTable(table)); TEST_CHECK(deleteTable("test_table_r")); TEST_CHECK(shutdownRecordManager()); free(table); free(sc); freeExpr(sel); TEST_DONE(); }
RC next(RM_ScanHandle *scan, Record *record) { // Setup mgmt data RM_ScanHandleMgmtData *shMgmtData = scan->mgmtData; RM_TableMgmtData *tableMgmtData = scan->rel->mgmtData; Value *result = (Value *)malloc(sizeof(Value)); // Do we have any tuples in the table to scan? if (tableMgmtData->numTuples == 0) { return RC_RM_NO_MORE_TUPLES; } do { // Have we already started a scan? if (shMgmtData->numScans == 0) { shMgmtData->rid.page = 1; shMgmtData->rid.slot = 0; RC pinPageResult; if (pinPageResult = pinPage(&tableMgmtData->bufferPool, &shMgmtData->pageHandle, shMgmtData->rid.page) != RC_OK) { return pinPageResult; } shMgmtData->page = (RM_Page*)shMgmtData->pageHandle.data; } // Scan until reach last tuple else if (shMgmtData->numScans < tableMgmtData->numTuples) { int pageSize = (int)(PAGE_SIZE - ((&((RM_Page*)0)->data) - ((char*)0))); int totalSlots = pageSize / getRecordSize(scan->rel->schema); shMgmtData->rid.slot++; if (shMgmtData->rid.slot == totalSlots) { shMgmtData->rid.page++; shMgmtData->rid.slot = 0; RC pinPageResult; if (pinPageResult = pinPage(&tableMgmtData->bufferPool, &shMgmtData->pageHandle, shMgmtData->rid.page) != RC_OK) { return pinPageResult; } shMgmtData->page = (RM_Page*)shMgmtData->pageHandle.data; } } // Scan over and nothing found else { return RC_RM_NO_MORE_TUPLES; } char *slotOffset = ((char*)&(shMgmtData->page)->data) + shMgmtData->rid.slot * getRecordSize(scan->rel->schema); int recordSize = getRecordSize(scan->rel->schema) - 1; memcpy(record->data, slotOffset + 1, recordSize); record->id.page = shMgmtData->rid.page; record->id.slot = shMgmtData->rid.slot; shMgmtData->numScans++; if (shMgmtData->cond != NULL) { evalExpr(record, (scan->rel)->schema, shMgmtData->cond, &result); } } while (!result->v.boolV); return RC_OK; }
// Bulk of work will be here // handling records in a table RC insertRecord(RM_TableData *rel, Record *record) { RM_TableMgmtData *tableMgmtData = rel->mgmtData; BM_MgmtData *bufferMgmtData = tableMgmtData->bufferPool.mgmtData; RID *rid = &record->id; RM_Page *page; char *slotOffset; // Do we have a free slot? if (tableMgmtData->nextFreeSlot > 0) { // We have a free slot for the record rid->page = tableMgmtData->nextFreeSlot; // Pin page to insert record RC pinPageResult; if (pinPageResult = pinPage(&tableMgmtData->bufferPool, &tableMgmtData->pageHandle, rid->page) != RC_OK) { return pinPageResult; } page = (RM_Page*)tableMgmtData->pageHandle.data; // Find the free slot for the record and save it rid->slot = findFreeSlot(page, rel->schema); if (rid->slot == NO_SLOT) { // Append new page, out of space RC unpinPageResult; if (unpinPageResult = unpinPage(&tableMgmtData->bufferPool, &tableMgmtData->pageHandle) != RC_OK) { return unpinPageResult; } if (appendEmptyBlock(&bufferMgmtData->fh) != RC_OK) { return RC_RM_INSERT_RECORD_FAIL; } rid->page = bufferMgmtData->fh.totalNumPages - 1; RC pinPageResult; if (pinPageResult = pinPage(&tableMgmtData->bufferPool, &tableMgmtData->pageHandle, rid->page) != RC_OK) { return pinPageResult; } //new page, set slot to 0 (first slot) page = (RM_Page*)tableMgmtData->pageHandle.data; rid->slot = 0; } } else { // No free slot so make new page for record RC appendEmptyBlockResult; if (appendEmptyBlock(&bufferMgmtData->fh) != RC_OK) { return RC_RM_INSERT_RECORD_FAIL; } rid->page = bufferMgmtData->fh.totalNumPages - 1; RC pinPageResult; if (pinPageResult = pinPage(&tableMgmtData->bufferPool, &tableMgmtData->pageHandle, rid->page) != RC_OK) { return pinPageResult; } page = (RM_Page*)tableMgmtData->pageHandle.data; rid->slot = 0; } // Finish writing the record now that we have slot information RC markDirtyResult; if (markDirtyResult = markDirty(&tableMgmtData->bufferPool, &tableMgmtData->pageHandle) != RC_OK) { return markDirtyResult; } // Add header offset to slot position for slot offset slotOffset = ((char*)&page->data) + (rid->slot * getRecordSize(rel->schema)); int recordSize = getRecordSize(rel->schema); memcpy(slotOffset + 1, record->data, recordSize); // Mark first byte of slot with tombstone information info *(char*)slotOffset = 1; // Update free slot information if (findFreeSlot(page, rel->schema) != NO_SLOT) { int pageNum = rid->page; addFreeSlot(tableMgmtData, page, rid->page); } RC unpinPageResult; if (unpinPageResult = unpinPage(&tableMgmtData->bufferPool, &tableMgmtData->pageHandle) != RC_OK) { return unpinPageResult; } tableMgmtData->numTuples++; return RC_OK; }
char *MultiPartHeader::data() { char *p=new char[getRecordSize()]; char *i = p; quint16 serverNumItems, serverId; quint64 artNum; quint16 sz16 = sizeof(quint16); quint16 sz32 = sizeof(quint32); quint16 sz64 = sizeof(quint64); *i = headerType; i++; memcpy(i, &postingDate, sz32); i +=sz32; memcpy(i, &downloadDate, sz32); i +=sz32; memcpy(i, &numParts, sz16); i+=sz16; serverNumItems=serverLowest.count(); memcpy(i, &serverNumItems, sz16); i+=sz16; for (lowestit=serverLowest.begin(); lowestit != serverLowest.end(); ++lowestit) { serverId=lowestit.key(); artNum=lowestit.value(); memcpy(i, &serverId, sz16); i+=sz16; memcpy(i, &artNum, sz64); i+=sz64; } memcpy(i, &multiPartKey, sz64); i +=sz64; memcpy(i, &missingParts, sz16); i+=sz16; memcpy(i, &status, sz16); i+=sz16; memcpy(i, &lines, sz32); i+=sz32; memcpy(i, &size, sz64); i+=sz64; // This is the area that maps the number of parts on each server quint16 serverPartItems=serverPart.count(); memcpy(i, &serverPartItems, sz16); i+=sz16; for (spmit=serverPart.begin() ; spmit != serverPart.end(); ++spmit) { serverId=spmit.key(); serverNumItems=spmit.value(); memcpy(i, &serverId, sz16); i+=sz16; memcpy(i, &serverNumItems, sz16); i+=sz16; } return p; }