Пример #1
0
        internal void RollbackTransactionChange(ITableEventRegistry registry)
        {
            lock (this) {
                // ASSERT: Can't do this is source is Read only.
                if (IsReadOnly)
                {
                    throw new InvalidOperationException("Can't rollback transaction journal, table is Read only.");
                }

                // Any rows added in the journal are marked as committed deleted and the
                // journal is then discarded.

                try {
                    // Mark all rows in the data_store as appropriate to the changes.
                    foreach (var tableEvent in registry)
                    {
                        if (tableEvent is TableRowEvent)
                        {
                            var rowEvent = (TableRowEvent)tableEvent;

                            if (rowEvent.EventType == TableRowEventType.Add)
                            {
                                var oldState = WriteRecordState(rowEvent.RowNumber, RecordState.CommittedRemoved);

                                if (oldState != RecordState.Uncommitted)
                                {
                                    WriteRecordState(rowEvent.RowNumber, oldState);

                                    throw new InvalidOperationException($"Record {rowEvent.RowNumber} was not in an uncommitted state.");
                                }

                                GC.DeleteRow(rowEvent.RowNumber);
                            }
                        }
                    }
                } catch (IOException e) {
                    throw new InvalidOperationException("IO Error: " + e.Message, e);
                }
            }
        }
Пример #2
0
        internal void CommitTransactionChange(long commitId, ITableEventRegistry change, IRowIndexSet indexSet)
        {
            lock (this) {
                // ASSERT: Can't do this if source is Read only.
                if (IsReadOnly)
                {
                    throw new InvalidOperationException("Can't commit transaction journal, table is Read only.");
                }

                // CHECK!
                // TODO: change.CommitId = commitId;

                try {
                    // Add this registry to the multi version table indices log
                    Registries.AddRegistry(change);

                    // Write the modified index set to the index store
                    // (Updates the index file)
                    CommitIndexSet(indexSet);

                    // Update the state of the committed added data to the file system.
                    // (Updates data to the allocation file)
                    //
                    // ISSUE: This can add up to a lot of changes to the allocation file and
                    //   the runtime could potentially be terminated in the middle of
                    //   the update.  If an interruption happens the allocation information
                    //   may be incorrectly flagged.  The type of corruption this would
                    //   result in would be;
                    //   + From an 'update' the updated record may disappear.
                    //   + From a 'delete' the deleted record may not delete.
                    //   + From an 'insert' the inserted record may not insert.
                    //
                    // Note, the possibility of this type of corruption occuring has been
                    // minimized as best as possible given the current architecture.
                    // Also note that is not possible for a table file to become corrupted
                    // beyond recovery from this issue.

                    foreach (var entry in change)
                    {
                        if (entry is TableRowEvent)
                        {
                            var rowEvent = (TableRowEvent)entry;
                            var rowIndex = rowEvent.RowNumber;

                            if (rowEvent.EventType == TableRowEventType.Add)
                            {
                                // Record commit added
                                var oldType = WriteRecordState(rowIndex, RecordState.CommittedAdded);

                                // Check the record was in an uncommitted state before we changed
                                // it.
                                if (oldType != RecordState.Uncommitted)
                                {
                                    WriteRecordState(rowIndex, oldType);
                                    throw new InvalidOperationException($"Record {rowIndex} of table {TableName} was not in an uncommitted state!");
                                }
                            }
                            else if (rowEvent.EventType == TableRowEventType.Remove)
                            {
                                // Record commit removed
                                var oldType = WriteRecordState(rowIndex, RecordState.CommittedRemoved);

                                // Check the record was in an added state before we removed it.
                                if (oldType != RecordState.CommittedAdded)
                                {
                                    WriteRecordState(rowIndex, oldType);
                                    throw new InvalidOperationException($"Record {rowIndex} of table {TableName} was not in an added state!");
                                }

                                // Notify collector that this row has been marked as deleted.
                                GC.DeleteRow(rowIndex);
                            }
                        }
                    }
                } catch (IOException e) {
                    throw new InvalidOperationException("IO Error: " + e.Message, e);
                }
            }
        }