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 });
                }
            }
        }
Example #4
0
        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
                    });
                }
            }
        }
Example #5
0
        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
                    });
                }
            }
        }
Example #6
0
        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);
        }