public void UpdateRecord(Transaction tid, string tableName, string key, Row record) { Console.WriteLine("DB: UpdateRecord {0}, key={1}, value={2}", tableName, key, record.DataString); //read active page tableName var pageTable = this.DiskReadPageTable(tableName); //modify page tableName var index = (from item in pageTable.RecordIndices where Trim(item.Key) == key select item).SingleOrDefault(); if (index == null) throw new RecordNotFoundException("record not found"); if (index.TransactionId != null && index.TransactionId == tid.Id && index.ActiveFileId == DeletededButNotCommitted) throw new RecordNotFoundException("record not found"); var page = DiskReadPage(tableName, index.PageIndex, index.ActiveFileId < 0 ? index.ShadowFileId : index.ActiveFileId); page.UpdateRow(record, index.RowIndex); if (index.ActiveFileId >= 0) page.FileId = page.FileId == 0 ? 1 : 0; //update page table index index.ShadowFileId = page.FileId; index.IsDirty = 1; index.TransactionId = tid.Id; if (!UseTwoPhaseCommit) { //write page into the shadow DiskWritePage(tableName, page, page.FileId); //save page table file UpdateShadowIdsForPage(pageTable, page.PageIndex, page.FileId, tid.Id); DiskWritePageTable(tableName, pageTable); CommitPages(tid, new List<Page> { page }); return; } lock (_transactionLogsForPrepare) { var log = new UpdateLog { OperationType = OperationType.Update, Image = record, PageIndex = page.PageIndex, RowIndex = index.RowIndex, PageShadowFileId = page.FileId, TableName = tableName, TransactionId = tid.Id, Key = key }; if (_transactionLogsForPrepare.ContainsKey(tid.Id)) { //for updating uncommitted insert, we just use the last update if (index.ActiveFileId == InsertedButNotCommitted) { var list = _transactionLogsForPrepare[tid.Id]; foreach (UpdateLog t in list) { if (t.TransactionId == tid.Id && Trim(t.Key) == key && t.OperationType == OperationType.Insert) { t.Image = log.Image; return; } } } else { var logs = _transactionLogsForPrepare[tid.Id]; var existingLog = (from l in logs where l.Key == key select l).FirstOrDefault(); if (existingLog != null) existingLog.Image = log.Image; else { logs.Add(log); } } } else { _transactionLogsForPrepare.Add(tid.Id, new List<UpdateLog> { log }); } } }
public void InsertRecord(Transaction tid, string tableName, string key, Row record) { var header = this.ReadDataFileHeader(tableName, 0); //read active page tableName var pageTable = this.DiskReadPageTable(tableName); //check if index is full if (!(from k in pageTable.RecordIndices where k.Key[0] == 0 select k).Any()) throw new ApplicationException("index is full"); //modify page tableName if ((from k in pageTable.RecordIndices where Trim(k.Key) == key select k).Any()) throw new ApplicationException("duplicate key " + key); //find an empty page var pageIndexTemp = Math.Abs(key.GetHashCode()) % header.TotalPageNum; var pageStart = pageIndexTemp; Page page = null; int rowId; lock (_insertdeleteLock) { bool pageInUse; do { pageInUse = false; foreach (var item in pageTable.RecordIndices) { if (item.Key[0] != 0 && item.PageIndex == pageIndexTemp) { pageInUse = true; page = DiskReadPage(tableName, item.PageIndex, item.ActiveFileId == InsertedButNotCommitted ? item.ShadowFileId : item.ActiveFileId); if (page.NextFreeRowIndex <= page.RowsPerPage) { break; } page = null; } } if (pageInUse) { if (page == null) pageIndexTemp = (++pageIndexTemp)%header.TotalPageNum; } else { page = DiskReadPage(tableName, pageIndexTemp, 0); break; } } while (pageIndexTemp != pageStart); if (page == null) throw new ApplicationException("out of page space"); rowId = page.InsertRow(record); if (!pageInUse) { page.FileId = page.FileId == 0 ? 1 : 0; } //update page table, active file id = -2, shadow file id points to data pageTable.InsertIndex(key, page.PageIndex, rowId, page.FileId, tid.Id); DiskWritePageTable(tableName, pageTable); if (!UseTwoPhaseCommit) { //save page tableName file UpdateShadowIdsForPage(pageTable, page.PageIndex, page.FileId, tid.Id); DiskWritePageTable(tableName, pageTable); //write page into the shadow DiskWritePage(tableName, page, page.FileId); CommitPages(tid, new List<Page> {page}); return; } //update the row index DiskWritePage(tableName, page, page.FileId); } lock (_transactionLogsForPrepare) { var log = new UpdateLog { OperationType = OperationType.Insert, Image = record, PageIndex = page.PageIndex, RowIndex = rowId, PageShadowFileId = page.FileId, TableName = tableName, TransactionId = tid.Id, Key = key }; if (_transactionLogsForPrepare.ContainsKey(tid.Id)) { _transactionLogsForPrepare[tid.Id].Add(log); } else { _transactionLogsForPrepare.Add(tid.Id, new List<UpdateLog> { log }); } } Console.WriteLine("DB: InsertRecord {0}, key={1}, value={2}", tableName, key, record.DataString); }
public void DeleteRecord(Transaction tid, string tableName, string key) { EnsureInitialized(); Console.WriteLine("DB: DeleteRecord {0}, key={1}", tableName, key); //read active page tableName var pageTable = this.DiskReadPageTable(tableName); var index = (from item in pageTable.RecordIndices where Trim(item.Key) == key select item).SingleOrDefault(); if (index == null) //|| //(index.TransactionId != null && index.TransactionId != tid.Id)) throw new RecordNotFoundException("record not found"); var page = DiskReadPage(tableName, index.PageIndex, index.ActiveFileId < 0 ? index.ShadowFileId : index.ActiveFileId); page.UpdateRow(page.CreateEmptyRow(), index.RowIndex); page.FileId = page.FileId == 0 ? 1 : 0; lock (this._insertdeleteLock) { //update page table index pageTable.MarkIndexDeleted(index, tid.Id); if (!UseTwoPhaseCommit) { //save page tableName file UpdateShadowIdsForPage(pageTable, page.PageIndex, page.FileId, tid.Id); DiskWritePageTable(tableName, pageTable); //write page into the shadow DiskWritePage(tableName, page, page.FileId); CommitPages(tid, new List<Page> {page}); return; } DiskWritePageTable(tableName, pageTable); } lock (_transactionLogsForPrepare) { var log = new UpdateLog { OperationType = OperationType.Detete, Image = page.CreateEmptyRow(), PageIndex = page.PageIndex, RowIndex = index.RowIndex, PageShadowFileId = page.FileId, TableName = tableName, TransactionId = tid.Id, Key = key }; if (_transactionLogsForPrepare.ContainsKey(tid.Id)) { var logs = _transactionLogsForPrepare[tid.Id]; var existingLog = (from l in logs where l.Key == key select l).FirstOrDefault(); if (existingLog != null) { if (existingLog.OperationType == OperationType.Insert) { //cancel the insertion logs.Remove(existingLog); logs.Add(log); } } else { logs.Add(log); } } else { _transactionLogsForPrepare.Add(tid.Id, new List<UpdateLog> { log }); } } }
public void DeleteRecord(Transaction tid, string tableName, string key) { EnsureInitialized(); Console.WriteLine("DB: DeleteRecord {0}, key={1}", tableName, key); //read active page tableName var pageTable = this.DiskReadPageTable(tableName); var index = (from item in pageTable.RecordIndices where Trim(item.Key) == key select item).SingleOrDefault(); if (index == null) //|| //(index.TransactionId != null && index.TransactionId != tid.Id)) { throw new RecordNotFoundException("record not found"); } var page = DiskReadPage(tableName, index.PageIndex, index.ActiveFileId < 0 ? index.ShadowFileId : index.ActiveFileId); page.UpdateRow(page.CreateEmptyRow(), index.RowIndex); page.FileId = page.FileId == 0 ? 1 : 0; lock (this._insertdeleteLock) { //update page table index pageTable.MarkIndexDeleted(index, tid.Id); if (!UseTwoPhaseCommit) { //save page tableName file UpdateShadowIdsForPage(pageTable, page.PageIndex, page.FileId, tid.Id); DiskWritePageTable(tableName, pageTable); //write page into the shadow DiskWritePage(tableName, page, page.FileId); CommitPages(tid, new List <Page> { page }); return; } DiskWritePageTable(tableName, pageTable); } lock (_transactionLogsForPrepare) { var log = new UpdateLog { OperationType = OperationType.Detete, Image = page.CreateEmptyRow(), PageIndex = page.PageIndex, RowIndex = index.RowIndex, PageShadowFileId = page.FileId, TableName = tableName, TransactionId = tid.Id, Key = key }; if (_transactionLogsForPrepare.ContainsKey(tid.Id)) { var logs = _transactionLogsForPrepare[tid.Id]; var existingLog = (from l in logs where l.Key == key select l).FirstOrDefault(); if (existingLog != null) { if (existingLog.OperationType == OperationType.Insert) { //cancel the insertion logs.Remove(existingLog); logs.Add(log); } } else { logs.Add(log); } } else { _transactionLogsForPrepare.Add(tid.Id, new List <UpdateLog> { log }); } } }
public void UpdateRecord(Transaction tid, string tableName, string key, Row record) { Console.WriteLine("DB: UpdateRecord {0}, key={1}, value={2}", tableName, key, record.DataString); //read active page tableName var pageTable = this.DiskReadPageTable(tableName); //modify page tableName var index = (from item in pageTable.RecordIndices where Trim(item.Key) == key select item).SingleOrDefault(); if (index == null) { throw new RecordNotFoundException("record not found"); } if (index.TransactionId != null && index.TransactionId == tid.Id && index.ActiveFileId == DeletededButNotCommitted) { throw new RecordNotFoundException("record not found"); } var page = DiskReadPage(tableName, index.PageIndex, index.ActiveFileId < 0 ? index.ShadowFileId : index.ActiveFileId); page.UpdateRow(record, index.RowIndex); if (index.ActiveFileId >= 0) { page.FileId = page.FileId == 0 ? 1 : 0; } //update page table index index.ShadowFileId = page.FileId; index.IsDirty = 1; index.TransactionId = tid.Id; if (!UseTwoPhaseCommit) { //write page into the shadow DiskWritePage(tableName, page, page.FileId); //save page table file UpdateShadowIdsForPage(pageTable, page.PageIndex, page.FileId, tid.Id); DiskWritePageTable(tableName, pageTable); CommitPages(tid, new List <Page> { page }); return; } lock (_transactionLogsForPrepare) { var log = new UpdateLog { OperationType = OperationType.Update, Image = record, PageIndex = page.PageIndex, RowIndex = index.RowIndex, PageShadowFileId = page.FileId, TableName = tableName, TransactionId = tid.Id, Key = key }; if (_transactionLogsForPrepare.ContainsKey(tid.Id)) { //for updating uncommitted insert, we just use the last update if (index.ActiveFileId == InsertedButNotCommitted) { var list = _transactionLogsForPrepare[tid.Id]; foreach (UpdateLog t in list) { if (t.TransactionId == tid.Id && Trim(t.Key) == key && t.OperationType == OperationType.Insert) { t.Image = log.Image; return; } } } else { var logs = _transactionLogsForPrepare[tid.Id]; var existingLog = (from l in logs where l.Key == key select l).FirstOrDefault(); if (existingLog != null) { existingLog.Image = log.Image; } else { logs.Add(log); } } } else { _transactionLogsForPrepare.Add(tid.Id, new List <UpdateLog> { log }); } } }
public void InsertRecord(Transaction tid, string tableName, string key, Row record) { var header = this.ReadDataFileHeader(tableName, 0); //read active page tableName var pageTable = this.DiskReadPageTable(tableName); //check if index is full if (!(from k in pageTable.RecordIndices where k.Key[0] == 0 select k).Any()) { throw new ApplicationException("index is full"); } //modify page tableName if ((from k in pageTable.RecordIndices where Trim(k.Key) == key select k).Any()) { throw new ApplicationException("duplicate key " + key); } //find an empty page var pageIndexTemp = Math.Abs(key.GetHashCode()) % header.TotalPageNum; var pageStart = pageIndexTemp; Page page = null; int rowId; lock (_insertdeleteLock) { bool pageInUse; do { pageInUse = false; foreach (var item in pageTable.RecordIndices) { if (item.Key[0] != 0 && item.PageIndex == pageIndexTemp) { pageInUse = true; page = DiskReadPage(tableName, item.PageIndex, item.ActiveFileId == InsertedButNotCommitted ? item.ShadowFileId : item.ActiveFileId); if (page.NextFreeRowIndex <= page.RowsPerPage) { break; } page = null; } } if (pageInUse) { if (page == null) { pageIndexTemp = (++pageIndexTemp) % header.TotalPageNum; } } else { page = DiskReadPage(tableName, pageIndexTemp, 0); break; } } while (pageIndexTemp != pageStart); if (page == null) { throw new ApplicationException("out of page space"); } rowId = page.InsertRow(record); if (!pageInUse) { page.FileId = page.FileId == 0 ? 1 : 0; } //update page table, active file id = -2, shadow file id points to data pageTable.InsertIndex(key, page.PageIndex, rowId, page.FileId, tid.Id); DiskWritePageTable(tableName, pageTable); if (!UseTwoPhaseCommit) { //save page tableName file UpdateShadowIdsForPage(pageTable, page.PageIndex, page.FileId, tid.Id); DiskWritePageTable(tableName, pageTable); //write page into the shadow DiskWritePage(tableName, page, page.FileId); CommitPages(tid, new List <Page> { page }); return; } //update the row index DiskWritePage(tableName, page, page.FileId); } lock (_transactionLogsForPrepare) { var log = new UpdateLog { OperationType = OperationType.Insert, Image = record, PageIndex = page.PageIndex, RowIndex = rowId, PageShadowFileId = page.FileId, TableName = tableName, TransactionId = tid.Id, Key = key }; if (_transactionLogsForPrepare.ContainsKey(tid.Id)) { _transactionLogsForPrepare[tid.Id].Add(log); } else { _transactionLogsForPrepare.Add(tid.Id, new List <UpdateLog> { log }); } } Console.WriteLine("DB: InsertRecord {0}, key={1}, value={2}", tableName, key, record.DataString); }