示例#1
0
        /// <summary>
        /// Attempts to insert a row into a btree
        /// </summary>
        /// <param name="insert">The row to insert</param>
        /// <returns>True if successful, otherwise false</returns>
        public bool InsertRow(RowInsert insert)
        {
            if (insert == null)
            {
                throw new ArgumentNullException(nameof(insert));
            }

            bool isSuccessful = false;

            BTreeContainer container;
            BTreeAddress   address = insert.Table.BTreeAddress;

            if (_cache.ContainsKey(insert.Table.BTreeAddress))
            {
                if (_cache.TryGetValue(address, out container))
                {
                    isSuccessful = container.TryInsertRow(insert);
                }
            }
            else
            {
                AddContainerToCache(address);
                if (_cache.TryGetValue(address, out container))
                {
                    isSuccessful = container.TryInsertRow(insert);
                }
            }

            return(isSuccessful);
        }
示例#2
0
        /// <summary>
        /// Pulls pages from disk into the tree and then attempts to insert the row into the first page it can fit into
        /// and then updates the page on disk
        /// </summary>
        /// <param name="row">The row to insert</param>
        private void InsertRowIntoFirstAvailablePage(RowInsert row)
        {
            int  nextPageId;
            Page page;

            do
            {
                // to do: we need to keep track of the page ids that we haven't loaded
                // into memory
                nextPageId = GetNextAvailablePageId();
                page       = _storage.GetPage(nextPageId, _address);
                AddPageToTree(page);

                if (TreeIsFullyLoaded())
                {
                    break;
                }

                // to do: what if the pages on disk are filled up and we need to add a brand new page here?
                // in other words, we can never exit the loop?
            }while (!page.CanInsertRow(row.Size));

            if (TreeIsFullyLoaded() && !page.CanInsertRow(row.Size))
            {
                AddRowToNewPage(row);
            }
            else
            {
                page.AddRow(row, GetMaxRowId() + 1);
                UpdatePageOnDisk(page);
            }
        }
示例#3
0
 public XactLine(RowInsert row)
 {
     XactId       = row.XactId;
     TableId      = row.Table.TableId;
     IsReconciled = false;
     Action       = XactLineAction.Insert;
     Data         = row.Values;
     LineNumber   = 0;
     Offset       = 0;
 }
示例#4
0
        /// <summary>
        /// Creates a new page and then adds the row to it; then adds the page to the tree and to storage
        /// </summary>
        /// <param name="row">The row to add</param>
        private void AddRowToNewPage(RowInsert row)
        {
            var page = new Page(GetNextPageId(), _address.TableId, _address.DatabaseId, _schema, _process);

            if (page.AddRow(row, GetMaxRowId() + 1))
            {
                AddPageToTree(page);
                AddPageToStorage(page);
            }
        }
示例#5
0
        /// <summary>
        /// Marks a insert xaction as reconciled in the file
        /// </summary>
        /// <param name="row">The row that was to be inserted</param>
        /// <returns>True if successful, otherwise false</returns>
        public bool MarkInsertXactAsReconciled(RowInsert row)
        {
            bool isSuccessful;

            _locker.EnterWriteLock();

            // this sucks

            string[] lines = File.ReadAllLines(FileName());

            var xacts = new List <XactLine>(lines.Length);

            foreach (var line in lines)
            {
                if (line.StartsWith("version"))
                {
                    continue;
                }

                if (line.Length == 0)
                {
                    continue;
                }

                var xact = new XactLine(line);
                if (xact.XactId == row.XactId)
                {
                    xact.IsReconciled = true;
                }

                xacts.Add(xact);
            }

            string[] linesToWrite = new string[lines.Length];

            int i = 0;

            foreach (var x in xacts)
            {
                linesToWrite[i] = x.ToString();
                i++;
            }

            File.WriteAllLines(FileName(), linesToWrite);

            // remove the xaction from the pending open transactions
            Guid value;

            isSuccessful = _unreconciledXacts.TryRemove(row.XactId, out value);

            _locker.ExitWriteLock();

            return(isSuccessful);
        }
示例#6
0
        /// <summary>
        /// Updates the db indexes if applicable for a row insert
        /// </summary>
        /// <param name="row">The row to b inserted</param>
        /// <returns>True if successful, otherwise false</returns>
        private bool UpdateIndexesForInsert(RowInsert row)
        {
            Table2 table = GetTable(row.Table.BTreeAddress);

            if (table.HasIndexes)
            {
                // need to update indexes if appropriate
            }

            //throw new NotImplementedException();
            return(true);
        }
示例#7
0
        /// <summary>
        /// Tries to add the row data to the btree and also update the data file and db directory data file on disk
        /// </summary>
        /// <param name="row">The row to be added</param>
        /// <returns>True if the operation was successful, otherwise false</returns>
        public bool TryInsertRow(RowInsert row)
        {
            if (row.Table.TableId != _address.TableId || row.Table.DatabaseId != _address.DatabaseId)
            {
                throw new InvalidOperationException("attempted to add row to incorrect btree");
            }

            bool result = false;

            if (GetContainerState() == BTreeContainerState.Ready)
            {
                SetContainerState(BTreeContainerState.LockedForInsert);

                lock (_treeLock)
                {
                    int nextPageId = 0;

                    if (TreeIsEmpty())
                    {
                        nextPageId = GetNextAvailablePageId();

                        // brand new table, need to add the 1st page.
                        if (nextPageId == 0)
                        {
                            AddRowToNewPage(row);
                            result = true;
                        }
                        else
                        {
                            InsertRowIntoFirstAvailablePage(row);
                            result = true;
                        }
                    }
                    else
                    {
                        if (!TreeIsFullyLoaded())
                        {
                            InsertRowIntoFirstAvailablePage(row);
                            result = true;
                        }
                        else
                        {
                            AddRowToNewPage(row);
                            result = true;
                        }
                    }
                }

                SetContainerState(BTreeContainerState.Ready);
            }

            return(result);
        }
示例#8
0
        /// <summary>
        /// Adds a row to this FrostDb instance
        /// </summary>
        /// <param name="rowForm">The row data to add</param>
        /// <returns>True if successful, otherwise false</returns>
        private bool AddRowLocally(RowForm2 rowForm)
        {
            RowInsert rowToInsert = new RowInsert(rowForm.Values, this.Schema, rowForm.Participant.Id, !rowForm.IsLocal(_process), rowForm.Address);

            if (_storage.RecordTransactionInLog(rowToInsert))
            {
                if (_cache.InsertRow(rowToInsert))
                {
                    if (_storage.UpdateIndexes(rowToInsert))
                    {
                        _cache.SyncTreeToDisk(rowToInsert.Address);
                        _storage.MarkTransactionAsReconciledInLog(rowToInsert);
                    }
                }
            }

            //throw new NotImplementedException();
            return(true);
        }
示例#9
0
        /// <summary>
        /// Attempts to write to the xact log for this database the row to be inserted. Will insert the xact as un-reconciled. This method is blocking.
        /// </summary>
        /// <param name="row">The row to be inserted.</param>
        /// <returns>True if successful, otherwise false.</returns>
        public bool WriteTransactionForInsert(RowInsert row)
        {
            bool isSuccessful;

            if (IsPendingReconciliation(row.XactId))
            {
                throw new InvalidOperationException($"xact {row.XactId.ToString()} is already in progress");
            }

            if (DoesFileExist())
            {
                _locker.EnterWriteLock();

                _unreconciledXacts.TryAdd(row.XactId, row.XactId);

                // to do - need to come up with xact file format
                // xact xactId tableId isReconciled <action> { Insert | Update | Delete } <data> { RowValues | RowId, RowValues | RowId }

                var item = new XactLine(row);

                using (var file = File.AppendText(FileName()))
                {
                    file.WriteLine(item.ToString());
                    file.Flush();
                }

                _locker.ExitWriteLock();

                isSuccessful = true;
            }
            else
            {
                isSuccessful = false;
            }

            // to do - is this right?
            return(isSuccessful);
        }
示例#10
0
 public void SetRowData(RowInsert row)
 {
     row.Values.ToBinaryFormat();
 }
示例#11
0
 /// <summary>
 /// Updates this insert action in the xact log that it has been reconciled against cache.
 /// </summary>
 /// <param name="row">The row that was reconciled</param>
 /// <returns>True if successful in writing to log, otherwise false</returns>
 public bool MarkTransactionAsReconciledInLog(RowInsert row)
 {
     return(_xactFile.MarkInsertXactAsReconciled(row));
 }
示例#12
0
 /// <summary>
 /// Records this insert action in the xact log. Will record it as unreconciled against cache.
 /// </summary>
 /// <param name="row">The row to record</param>
 /// <returns>True if successful in writing to log, otherwise false</returns>
 public bool RecordTransactionInLog(RowInsert row)
 {
     return(_xactFile.WriteTransactionForInsert(row));
 }
示例#13
0
 public bool UpdateIndexes(RowInsert row)
 {
     return(UpdateIndexesForInsert(row));
 }
示例#14
0
        /// <summary>
        /// Attempts to add a row to this page and then reconcile the xact on disk
        /// </summary>
        /// <param name="row">The row to be added</param>
        /// <param name="rowId">The id for this row. This should be the next available rowId</param>
        /// <returns>True if succesful, otherwise false</returns>
        public bool AddRow(RowInsert row, int rowId)
        {
            bool result = false;

            if (row == null)
            {
                throw new ArgumentNullException(nameof(row));
            }

            row.OrderByByteFormat();

            // rent 1
            byte[] preamble = RentByteArrayFromPool(DatabaseConstants.SIZE_OF_ROW_PREAMBLE);
            Row2.BuildRowPreamble(ref preamble, rowId, !row.IsReferenceInsert);

            byte[] rowData = null;
            if (row.IsReferenceInsert)
            {
                // need to save off the GUID id

                // rent 2
                rowData = RentByteArrayFromPool(DatabaseConstants.PARTICIPANT_ID_SIZE);
                row.ToBinaryFormat(ref rowData);
            }
            else
            {
                // need to save off the size of the row + all the actual row data

                // rent 2
                rowData = RentByteArrayFromPool(row.Size + DatabaseConstants.SIZE_OF_ROW_SIZE);
                row.ToBinaryFormat(ref rowData);
            }

            // rent 3
            byte[] totalRowData = RentByteArrayFromPool(preamble.Length + rowData.Length);

            // combine the preamble and the row data together
            Array.Copy(preamble, 0, totalRowData, 0, preamble.Length);
            Array.Copy(rowData, 0, totalRowData, preamble.Length, rowData.Length);

            // to do: add totalRowData to this Page's data
            if (CanInsertNewRow(totalRowData.Length))
            {
                Array.Copy(totalRowData, 0, _data, GetNextAvailableRowOffset(), totalRowData.Length);
                _totalBytesUsed += totalRowData.Length;
                _totalRows++;
                SaveTotalRows();
                result = true;
            }
            else
            {
                // we need to add this row to the next page because we are out of room on this page
                // throw exception here or... ?
            }

            _pendingXacts.Add(row.XactId);

            // return 1, 2, 3
            ReturnByteArrayToPool(ref preamble);
            ReturnByteArrayToPool(ref rowData);
            ReturnByteArrayToPool(ref totalRowData);

            return(result);
        }