/// <summary> /// Iterates over this page's _data and populates the supplied array with structs representing the rows /// </summary> /// <param name="rows">An array of RowStruct to populate</param> private void IterateOverData(ref RowStruct[] rows) { var dataSpan = new Span <byte>(_data); int currentOffset = DatabaseConstants.SIZE_OF_PAGE_PREAMBLE; int currentRowNum = 0; while (currentOffset < DatabaseConstants.PAGE_SIZE) { int rowId; bool isLocal; int sizeOfRow; RowPreamble.Parse(dataSpan.Slice(currentOffset, DatabaseConstants.SIZE_OF_ROW_PREAMBLE), out rowId, out isLocal); // check for end of data row identifier if (isLocal && rowId == DatabaseConstants.END_OF_ROW_DATA_ID) { break; } if (currentRowNum >= _totalRows) { break; } currentOffset += DatabaseConstants.SIZE_OF_ROW_PREAMBLE; if (isLocal) { var values = new RowValue2[_schema.Columns.Length]; // we need the size of the row to parse how far along we should go in the array (span). // we will however not adjust the offset since the method LocalRowBodyFromBinary includes parsing the rowSize prefix (an int32 size (4 bytes)). sizeOfRow = BitConverter.ToInt32(dataSpan.Slice(currentOffset, DatabaseConstants.SIZE_OF_ROW_SIZE)); int rowSize; // this isn't really needed, but it's a required param of the method below Row2.LocalRowBodyFromBinary(dataSpan.Slice(currentOffset, sizeOfRow), out rowSize, ref values, _schema.Columns); //rows.Add(new Row2(rowId, isLocal, _schema.Columns, _process.Id.Value, values, sizeOfRow)); rows[currentRowNum] = new RowStruct { IsLocal = isLocal, RowId = rowId, ParticipantId = Guid.Empty, RowSize = sizeOfRow, Values = values }; currentOffset += sizeOfRow; currentRowNum++; } else { sizeOfRow = DatabaseConstants.PARTICIPANT_ID_SIZE; Guid particpantId = DatabaseBinaryConverter.BinaryToGuid(dataSpan.Slice(currentOffset, sizeOfRow)); //rows.Add(new Row2(rowId, isLocal, particpantId, sizeOfRow, _schema.Columns)); rows[currentRowNum] = new RowStruct { IsLocal = isLocal, ParticipantId = particpantId, RowSize = sizeOfRow, RowId = rowId, Values = null }; currentOffset += sizeOfRow; currentRowNum++; } } }
/// <summary> /// Returns the data in binary format for this row. This method takes an array reference (usually passed in from ArrayPool). /// This array must be sized correctly (use Size attribute + size of INT to account for row size prefix). /// This does not include the row preamble. If local, it will prefix with the size of the row (this does not include the Size of the Row Preamble - only the size of the fixed + variable size data). /// </summary> /// <param name="returnedArray">A source array reference (usually from ArrayPool). This must be sized correctly (use Size attribute).</param> /// <returns>Row values in a binary array</returns> public void ToBinaryFormat(ref byte[] array) { if (!IsReferenceInsert) { Row2.ValuesToBinaryFormat(ref array, Values); } else { Row2.ParticipantToBinaryFormat(ref array, ParticipantId.Value); } }
/// <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); }