Ejemplo n.º 1
0
        public DbIndex GetIndex(string columnName)
        {
            CheckColumnNameValid(columnName);

            StringDictionary p        = TableProperties;
            long             columnId = p.GetValue(columnName + ".id", -1);

            if (columnId == -1)
            {
                throw new ApplicationException("Column '" + columnName + "' not found");
            }

            if (!p.GetValue(columnName + ".index", false))
            {
                throw new ApplicationException("Column '" + columnName + "' is not indexed");
            }

            // Fetch the index object,
            IDataFile   df   = GetDataFile(GetIndexIdKey(columnId));
            SortedIndex list = new SortedIndex(df);

            // And return it,
            IIndexedObjectComparer <string> comparer = GetIndexComparerFor(columnName, columnId);

            return(new DbIndex(this, currentVersion, comparer, columnId, list));
        }
Ejemplo n.º 2
0
        public void Update(DbRow row)
        {
            if (rowBufferId != 0)
            {
                throw new ApplicationException("State error: previous table operation not completed");
            }

            // Check row is currently indexed,
            long        rowid = row.RowId;
            IDataFile   df    = GetDataFile(rowIndexKey);
            SortedIndex rows  = new SortedIndex(df);

            if (!rows.ContainsSortKey(rowid))
            {
                throw new ApplicationException("Row being updated is not in the table");
            }

            if (rowBuffer == null)
            {
                rowBuffer = new Dictionary <string, string>();
            }

            rowBufferId = rowid;

            // Copy from the existing data in the row,
            string[] cols = ColumnNames;
            foreach (string col in cols)
            {
                string val = row.GetValue(col);
                if (val != null)
                {
                    rowBuffer[col] = val;
                }
            }
        }
Ejemplo n.º 3
0
        public Key RemoveItem(String name)
        {
            ++directoryVersion;

            StringDictionary pset = new StringDictionary(GetDataFile(propertySetKey));
            long             id   = pset.GetValue <long>(name, -1);

            // Assert the item is stored,
            if (id == -1)
            {
                throw new ApplicationException("Item not found: " + name);
            }

            pset.SetValue(name, null);
            SortedIndex iset = new SortedIndex(GetDataFile(indexSetKey));

            iset.Remove(name, id, collator);

            // Delete the associated datafile
            Key       k  = GetItemKey(id);
            IDataFile df = GetDataFile(k);

            df.Delete();

            return(k);
        }
Ejemplo n.º 4
0
        public DbRowCursor GetReverseCursor()
        {
            IDataFile   df   = GetDataFile(rowIndexKey);
            SortedIndex list = new SortedIndex(df);

            return(new DbRowCursor(this, currentVersion, new DbIndex.ReverseCursor(list.GetCursor())));
        }
Ejemplo n.º 5
0
        public Key AddItem(string name)
        {
            ++directoryVersion;

            StringDictionary pset = new StringDictionary(GetDataFile(propertySetKey));

            // Assert the item isn't already stored,
            if (pset.GetValue <long>(name, -1) != -1)
            {
                throw new ApplicationException("Item already exists: " + name);
            }

            // Generate a unique identifier for the name,
            long id = GenerateId();

            pset.SetValue(name, id);
            SortedIndex iset = new SortedIndex(GetDataFile(indexSetKey));

            iset.Insert(name, id, collator);

            Key itemKey = GetItemKey(id);

            IDataFile df = GetDataFile(itemKey);

            try {
                BinaryWriter dout = new BinaryWriter(new DataFileStream(df), Encoding.Unicode);
                dout.Write(name);
            } catch (IOException e) {
                throw new ApplicationException(e.Message);
            }

            return(itemKey);
        }
Ejemplo n.º 6
0
        public int Delete(IEnumerator <DbRow> rows)
        {
            int deleteCount = 0;

            while (rows.MoveNext())
            {
                DbRow row = rows.Current;
                if (row == null)
                {
                    continue;
                }

                long        rowid     = row.RowId;
                IDataFile   df        = GetDataFile(rowIndexKey);
                SortedIndex rowsIndex = new SortedIndex(df);
                if (rowsIndex.ContainsSortKey(rowid))
                {
                    // Remove the row from the main index,
                    RemoveRowFromRowSet(rowid);
                    // Remove the row from any indexes defined on the table,
                    RemoveRowFromIndexSet(rowid);
                    // Delete the row file
                    IDataFile rowFile = GetDataFile(GetRowIdKey(rowid));
                    rowFile.Delete();

                    // Add this event to the transaction log,
                    AddTransactionEvent("deleteRow", rowid);
                    deleteCount++;
                }
            }

            ++currentVersion;
            return(deleteCount);
        }
Ejemplo n.º 7
0
        private void RemoveRowFromRowSet(long rowid)
        {
            // Get the index object
            IDataFile   df   = GetDataFile(rowIndexKey);
            SortedIndex rows = new SortedIndex(df);

            // Remove the row in rowid value sorted order
            rows.RemoveSortKey(rowid);
        }
Ejemplo n.º 8
0
        private void AddRowToRowSet(long rowid)
        {
            // Get the index object
            IDataFile   df   = GetDataFile(rowIndexKey);
            SortedIndex rows = new SortedIndex(df);

            // Add the row in rowid value sorted order
            rows.InsertSortKey(rowid);
        }
Ejemplo n.º 9
0
 private void AddRowToIndexSet(long rowid)
 {
     // Get the set of columns that are indexed in this table,
     string[] indexedCols = IndexedColumns;
     foreach (String col in indexedCols)
     {
         // Resolve the column name to an id, turn it into a OrderedList64Bit,
         // and insert the row in the correct location in the index,
         long        columnid = GetColumnId(col);
         IDataFile   df       = GetDataFile(GetIndexIdKey(columnid));
         SortedIndex index    = new SortedIndex(df);
         IIndexedObjectComparer <string> indexComparer = GetIndexComparerFor(col, columnid);
         index.Insert(GetValue(rowid, columnid), rowid, indexComparer);
     }
 }
Ejemplo n.º 10
0
 public void CheckTableDataDelete(String table, long rowid)
 {
     // Is it in the modification set?
     if (tableDataChanged != null)
     {
         DbTable t;
         if (tableDataChanged.TryGetValue(table, out t))
         {
             // Yes, so check if the given row in the modification set,
             SortedIndex deleteSet = t.Deletes;
             if (deleteSet.ContainsSortKey(rowid))
             {
                 // Yes, so generate a commit fault,
                 throw new CommitFaultException(String.Format("Row in Table ''{0}'' was modified by a concurrent transaction",
                                                              table));
             }
         }
     }
 }
Ejemplo n.º 11
0
        private void BuildIndex(long columnid, IIndexedObjectComparer <string> indexComparer)
        {
            // Get the index object
            IDataFile df = GetDataFile(GetIndexIdKey(columnid));
            // Get the index and clear it,
            SortedIndex index = new SortedIndex(df);

            index.Clear();

            // For each row in this table,
            foreach (DbRow row in this)
            {
                // Get the column value and the rowid
                string columnValue = row.GetValue(columnid);
                long   rowid       = row.RowId;
                // Add it into the index,
                index.Insert(columnValue, rowid, indexComparer);
            }
            // Done.
        }
Ejemplo n.º 12
0
        public void BeginUpdate(long rowid)
        {
            if (rowBufferId != 0)
            {
                throw new ApplicationException("State error: previous table operation not completed");
            }

            // Check row is currently indexed,
            IDataFile   df   = GetDataFile(rowIndexKey);
            SortedIndex rows = new SortedIndex(df);

            if (!rows.ContainsSortKey(rowid))
            {
                throw new ApplicationException("Row being updated is not in the table");
            }

            if (rowBuffer == null)
            {
                rowBuffer = new Dictionary <string, string>();
            }

            rowBufferId = rowid;
        }
Ejemplo n.º 13
0
        internal void PrepareForCommit()
        {
            // Write the transaction log for this table,
            IDataFile df = GetDataFile(AddLog);

            df.Delete();
            SortedIndex addlist = new SortedIndex(df);

            foreach (long v in addRowList)
            {
                addlist.InsertSortKey(v);
            }

            df = GetDataFile(RemoveLog);
            df.Delete();
            SortedIndex deletelist = new SortedIndex(df);

            foreach (long v in deleteRowList)
            {
                if (addlist.ContainsSortKey(v))
                {
                    addlist.RemoveSortKey(v);
                }
                else
                {
                    deletelist.InsertSortKey(v);
                }
            }

            // Set the id gen key
            if (currentIdGen != -1)
            {
                StringDictionary p = TableProperties;
                p.SetValue("k", currentIdGen);
            }
        }
Ejemplo n.º 14
0
        public void Delete(DbRow row)
        {
            long        rowid = row.RowId;
            IDataFile   df    = GetDataFile(rowIndexKey);
            SortedIndex rows  = new SortedIndex(df);

            if (!rows.ContainsSortKey(rowid))
            {
                throw new ApplicationException("Row being deleted is not in the table");
            }

            // Remove the row from the main index,
            RemoveRowFromRowSet(rowid);
            // Remove the row from any indexes defined on the table,
            RemoveRowFromIndexSet(rowid);
            // Delete the row file
            IDataFile rowFile = GetDataFile(GetRowIdKey(rowid));

            rowFile.Delete();

            // Add this event to the transaction log,
            AddTransactionEvent("deleteRow", rowid);
            ++currentVersion;
        }
Ejemplo n.º 15
0
        public DataAddress Commit(IPathConnection connection, DataAddress rootNode)
        {
            // Turn the proposal into a proposed_transaction,
            ITransaction  t = connection.CreateTransaction(rootNode);
            DbTransaction proposedTransaction = new DbTransaction(null, rootNode, t);

            try {
                // Fetch the base root from the proposed_transaction log,
                TextReader reader      = proposedTransaction.GetLogReader();
                string     baseRootStr = reader.ReadLine();
                // If 'base_root_str' is "no base root" then it means we are commiting
                // an introduced transaction that is not an iteration of previous
                // snapshots.
                if (baseRootStr.Equals("no base root"))
                {
                    // In which case, we publish the proposed snapshot unconditionally
                    // and return.
                    connection.Publish(rootNode);
                    return(rootNode);
                }

                DataAddress baseRoot = DataAddress.Parse(baseRootStr);

                // Find all the entries since this base
                DataAddress[] roots = connection.GetSnapshots(baseRoot);

                // If there are no roots, we can publish the proposed_transaction
                // unconditionally
                if (roots.Length == 0)
                {
                    connection.Publish(rootNode);
                    return(rootNode);
                }

                // Check historical log for clashes, and if none, replay the commands
                // in the log.

                // For each previous root, we build a structure that can answer the
                // following questions;
                // * Is file [name] created, deleted or changed in this root?
                // * Is table [name] created or deleted in this root?
                // * Is table [name] structurally changed in this root?
                // * Has row [rowid] been deleted in table [name] in this root?

                RootEvents[] rootEventSet = new RootEvents[roots.Length];
                int          i            = 0;

                // TODO: RootEvents is pre-computed information which we could
                //   store in a local cache for some speed improvements, so we don't
                //   need to walk through through the same data multiple times.

                foreach (DataAddress root in roots)
                {
                    RootEvents rootEvents = new RootEvents();
                    rootEventSet[i] = rootEvents;
                    ++i;
                    // Create a transaction object for this root
                    ITransaction  rootT           = connection.CreateTransaction(root);
                    DbTransaction rootTransaction = new DbTransaction(null, root, rootT);
                    // Make a reader object for the log,
                    TextReader rootReader = rootTransaction.GetLogReader();
                    // Read the base root from this transaction,
                    String baseRootParent = rootReader.ReadLine();
                    // If 'bast_root_parent' is 'no base root' then it means a version
                    // has been introduced that is not an iteration of previous
                    // snapshots. In this case, it is not possible to merge updates
                    // therefore we generate a commit fault.
                    if (baseRootParent.Equals("no base root"))
                    {
                        throw new CommitFaultException("Transaction history contains introduced version.");
                    }

                    // Go through each log entry and determine if there's a clash,
                    string rootLine = rootReader.ReadLine();
                    while (rootLine != null)
                    {
                        String mfile = rootLine.Substring(2);
                        // This represents a file modification,
                        bool unknownCommand = false;
                        if (rootLine.StartsWith("F"))
                        {
                            rootEvents.SetFileChange(mfile);
                        }
                        // This is a table modification,
                        else if (rootLine.StartsWith("T"))
                        {
                            char c = rootLine[1];
                            // If this is a table create or delete event,
                            if (c == 'C' || c == 'D')
                            {
                                rootEvents.SetTableCreateOrDelete(mfile);
                            }
                            // This is a table structural change,
                            else if (c == 'S')
                            {
                                rootEvents.SetTableStructuralChange(mfile);
                            }
                            // This is a table data change event,
                            else if (c == 'M')
                            {
                                DbTable table = rootTransaction.GetTable(mfile);
                                rootEvents.SetTableDataChange(mfile, table);
                            }
                            else
                            {
                                unknownCommand = true;
                            }
                        }
                        else
                        {
                            unknownCommand = true;
                        }
                        if (unknownCommand)
                        {
                            throw new ApplicationException("Unknown transaction command: " + rootLine);
                        }
                        // Read the next log entry,
                        rootLine = rootReader.ReadLine();
                    }
                }

                // Now we have a set of RootEvents objects that describe what
                // happens in each previous root.

                // Now replay the events in the proposal transaction in the latest
                // transaction.

                // A transaction representing the current state,
                DataAddress   currentRoot        = connection.GetSnapshot();
                ITransaction  currentT           = connection.CreateTransaction(currentRoot);
                DbTransaction currentTransaction = new DbTransaction(null, currentRoot, currentT);
                String        entry = reader.ReadLine();
                while (entry != null)
                {
                    String mfile = entry.Substring(2);
                    // If it's a file entry, we need to check the file hasn't been
                    // changed in any way in any roots
                    if (entry.StartsWith("F"))
                    {
                        foreach (RootEvents events in rootEventSet)
                        {
                            events.CheckFileChange(mfile);
                        }

                        // All checks passed, so perform the operation
                        currentTransaction.ReplayFileLogEntry(entry, proposedTransaction);
                    }
                    // If it's a table entry,
                    else if (entry.StartsWith("T"))
                    {
                        // Check that a table with this name hasn't been created, deleted
                        // or modified,
                        foreach (RootEvents events in rootEventSet)
                        {
                            // This fails on any event on this table, except a data change
                            // (insert or delete)
                            events.CheckTableMetaChange(mfile);
                        }
                        // The type of operation,
                        char c = entry[1];
                        // Is it a table structural change?
                        if (c == 'S')
                        {
                            // A structural change can only happen if all the roots leave the
                            // table untouched,
                            foreach (RootEvents events in rootEventSet)
                            {
                                // This fails if it finds a delete event for this rowid
                                events.CheckTableDataChange(mfile);
                            }
                        }
                        // Is it a table modification command?
                        else if (c == 'M')
                        {
                            // This is a table modification, we need to check the rowid
                            // logs and look for possible clashes,
                            // The delete set from the proposed transaction,
                            DbTable      proposedTable = proposedTransaction.GetTable(mfile);
                            SortedIndex  deleteSet     = proposedTable.Deletes;
                            IIndexCursor dsi           = deleteSet.GetCursor();
                            while (dsi.MoveNext())
                            {
                                long rowid = dsi.Current;
                                foreach (RootEvents events in rootEventSet)
                                {
                                    // This fails if it finds a delete event for this rowid
                                    events.CheckTableDataDelete(mfile, rowid);
                                }
                            }
                        }
                        // Go through each root, if the data in the table was changed
                        // by any of the roots, we set 'has_data_changes' to true;
                        bool hasDataChanges = false;
                        foreach (RootEvents events in rootEventSet)
                        {
                            if (events.HasTableDataChanges(mfile))
                            {
                                hasDataChanges = true;
                            }
                        }

                        // Ok, checks passed, so reply all the data changes on the table
                        currentTransaction.ReplayTableLogEntry(entry, proposedTransaction, hasDataChanges);
                    }
                    else
                    {
                        throw new ApplicationException("Unknown transaction command: " + entry);
                    }

                    // Read the next log entry,
                    entry = reader.ReadLine();
                }

                // Refresh the transaction log
                currentTransaction.RefreshTransactionLog();

                // Flush and publish the change
                DataAddress finalRoot = connection.CommitTransaction(currentT);
                connection.Publish(finalRoot);

                // Done.
                return(finalRoot);
            } catch (IOException e) {
                throw new ApplicationException("IO Error: " + e.Message);
            }
        }
Ejemplo n.º 16
0
 public ItemList(Directory directory, SortedIndex sortedIndex)
 {
     this.directory   = directory;
     this.sortedIndex = sortedIndex;
     localDirVersion  = directory.directoryVersion;
 }
Ejemplo n.º 17
0
        internal void MergeFrom(DbTable from, bool structuralChange, bool historicDataChange)
        {
            // If structural_change is true, this can only happen if 'from' is the
            // immediate child of this table.
            // If 'historic_data_change' is false, this can only happen if 'from' is
            // the immediate child of this table.

            // Handle structural change,
            if (structuralChange || historicDataChange == false)
            {
                // Fetch all the indexes,
                string[]    fromIndexes  = from.IndexedColumns;
                List <long> fromIndexIds = new List <long>(fromIndexes.Length);
                foreach (String findex in fromIndexes)
                {
                    fromIndexIds.Add(from.GetColumnId(findex));
                }
                // Copy them into here,
                CopyFile(from.GetDataFile(from.rowIndexKey), GetDataFile(rowIndexKey));
                foreach (long indexId in fromIndexIds)
                {
                    // Copy all the indexes here,
                    CopyFile(from.GetDataFile(from.GetIndexIdKey(indexId)), GetDataFile(GetIndexIdKey(indexId)));
                }

                // Move the column and index information into this table,
                CopyFile(from.propertiesFile, propertiesFile);

                // Copy the transaction logs
                CopyFile(from.GetDataFile(from.AddLog), GetDataFile(AddLog));
                CopyFile(from.GetDataFile(from.RemoveLog), GetDataFile(RemoveLog));

                // Replay the add and remove transaction events
                SortedIndex addEvents    = new SortedIndex(from.GetDataFile(from.AddLog));
                SortedIndex removeEvents = new SortedIndex(from.GetDataFile(from.RemoveLog));

                // Adds
                foreach (long rowid in addEvents)
                {
                    CopyFile(from.GetDataFile(from.GetRowIdKey(rowid)), GetDataFile(GetRowIdKey(rowid)));
                }

                // Removes
                foreach (long rowid in removeEvents)
                {
                    // Delete the row data file,
                    GetDataFile(GetRowIdKey(rowid)).Delete();
                }
            }
            else
            {
                // If we are here, then we are merging a change that isn't a structural
                // change, and there are historical changes. Basically this means we
                // need to replay the add and remove events only, but more strictly,

                // Replay the add and remove transaction events
                SortedIndex addEvents    = new SortedIndex(from.GetDataFile(from.AddLog));
                SortedIndex removeEvents = new SortedIndex(from.GetDataFile(from.RemoveLog));

                // Adds
                foreach (long fromRowid in addEvents)
                {
                    // Generate a new id for the row,
                    long toRowid = GenerateId();
                    // Copy record to the new id in this table,
                    CopyFile(from.GetDataFile(from.GetRowIdKey(fromRowid)), GetDataFile(GetRowIdKey(toRowid)));
                    // Update indexes,
                    AddRowToRowSet(toRowid);
                    AddRowToIndexSet(toRowid);
                    // Add this event to the transaction log,
                    AddTransactionEvent("insertRow", toRowid);
                }

                // Removes
                foreach (long fromRowid in removeEvents)
                {
                    // Update indexes,
                    RemoveRowFromRowSet(fromRowid);
                    RemoveRowFromIndexSet(fromRowid);

                    // Delete the row data file,
                    GetDataFile(GetRowIdKey(fromRowid)).Delete();

                    // Add this event to the transaction log,
                    AddTransactionEvent("deleteRow", fromRowid);
                }

                // Write out the transaction logs,
                PrepareForCommit();
            }

            // Invalidate all the cached info,
            columnIdMap      = null;
            cachedColumnList = null;
            cachedIndexList  = null;

            ++currentVersion;
        }
Ejemplo n.º 18
0
 public Cursor(SortedIndex index, long start, long end)
 {
     this.index = index;
     this.end   = end;
     this.start = start;
 }