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 UpsertRecord(Transaction tid, string tableName, string key, Row record)
        {
            EnsureInitialized();

            //get page table first
            var pageTable = this.DiskReadPageTable(tableName);

            if (!(from k in pageTable.RecordIndices where Trim(k.Key) == key select k).Any())
            {
                InsertRecord(tid, tableName, key, record);
            }
            else
            {
                UpdateRecord(tid, tableName, key, record);
            }
        }
Exemplo n.º 3
0
        public void Decode(byte[] pageData)
        {
            if ("P$" != _encoder.GetString(pageData, 0, 2))
                throw new ApplicationException("Invalid page - Page Header");

            if (this.PageIndex != BitConverter.ToInt32(pageData, 2))
                throw new ApplicationException("Invalid Page - PageIndex");

            NextFreeRowIndex = BitConverter.ToInt32(pageData, 2 + 4);

            _rows = new Row[this.RowsPerPage];

            for (var i = 0; i < RowsPerPage; i++)
            {
                var buffer = new byte[RowSize];
                Array.Copy(pageData, Page.PageHeadSize + i * RowSize, buffer, 0, this.RowSize);
                _rows[i] = new Row(this.RowSize) { Data = buffer };
            }
        }
        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);
        }
Exemplo n.º 5
0
 public Row CreateEmptyRow()
 {
     var r = new Row(this.RowSize);
     return r;
 }
Exemplo n.º 6
0
 public void UpdateRow(Row row, int index)
 {
     IsDirty = true;
     Array.Copy(row.Data, _rows[index].Data, row.Data.Length < RowSize ? row.Data.Length : RowSize);
 }
Exemplo n.º 7
0
 public int InsertRow(Row row)
 {
     var rowId = NextFreeRowIndex++;
     IsDirty = true;
     Array.Copy(row.Data, _rows[rowId].Data, row.Data.Length < RowSize ? row.Data.Length : RowSize);
     return rowId;
 }
Exemplo n.º 8
0
 public Row GetRow(int i)
 {
     var r = new Row(this.RowSize);
     Array.Copy(_rows[i].Data, r.Data, RowSize);
     return r;
 }
        public void RowTest()
        {
            var row = new Row(100) {Data = _encoder.GetBytes("row data read/write")};
            Assert.AreEqual("row data read/write", row.DataString);

            row.Data = _encoder.GetBytes("abc");
            Assert.AreEqual("abc", row.DataString);
        }