Beispiel #1
0
        /// <summary>
        ///Commits current transaction. Optionally if <paramref name="withOmit"/> set to true erases transaction from undo history
        /// </summary>
        /// <param name="withOmit"></param>
        /// <returns></returns>
        public int Commit(bool withOmit)
        {
            this.ValidateModification();
            int v = this.Version;

            RuntimeHelpers.PrepareConstrainedRegions();
            try {} finally {
                if (withOmit)
                {
                    ValueList <TransactionType> .Address address = this.version.ItemAddress(this.version.Count - 1);
                    Debug.Assert(address.Page[address.Index] == TransactionType.Edit, "Only edit transactions can be omitted");
                    address.Page[address.Index] = TransactionType.Omit;
                }
                this.CompletedVersion = v;
                this.editorThread     = null;
                this.editor           = null;
                LockFreeSync.WriteBarrier();
            }
            EventHandler handler = this.Committed;

            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
            return(v);
        }
        /// <summary>
        /// Shrinks list to new size.
        /// It is guarantee that space allocated by PrepareAdd will not be freed here.
        /// </summary>
        /// <param name="newSize"></param>
        public void Shrink(int newSize)
        {
            int oldSize = this.Count;

            if (newSize < oldSize)
            {
                this.Count = newSize;
                LockFreeSync.WriteBarrier();
                for (int i = newSize >> LogPageSize; i < this.page.Length; i++)
                {
                    TRow[] p = this.page[i];
                    if (p == null)
                    {
                        return;
                    }
                    for (int j = newSize & IndexOnPageMask; j < p.Length; j++)
                    {
                        if (oldSize <= newSize++)
                        {
                            return;
                        }
                        p[j] = default;
                    }
                }
            }
            else if (oldSize < newSize)
            {
                throw new ArgumentOutOfRangeException(nameof(newSize));
            }
        }
        /// <summary>
        /// Gets record in the specified version
        /// </summary>
        /// <param name="rowId"></param>
        /// <param name="version"></param>
        /// <param name="data"></param>
        public void GetData(RowId rowId, int version, out TRecord data)
        {
            if (version != 0)
            {
                this.ValidateVersion(version);
            }
            int pointIndex = this.snap.Count - 1;

            ValueList <Snap> .Address snapAddress = this.snap.ItemAddress(pointIndex);
            while (version < snapAddress.Page[snapAddress.Index].Version)
            {
                snapAddress = this.snap.ItemAddress(--pointIndex);
            }
            if (!(0 <= rowId.Value && rowId.Value < snapAddress.Page[snapAddress.Index].TableSize))
            {
                throw new ArgumentOutOfRangeException(nameof(rowId));
            }
            // cache log size here. the original can only grow in time
            int logSize = snapAddress.Page[snapAddress.Index].LogSize;

            ValueList <Row> .Address rowAddress = this.table.ItemAddress(rowId.Value);
            if (rowAddress.Page[rowAddress.Index].LogIndex < logSize)
            {
                // so the latest version of data was requested.
                data = rowAddress.Page[rowAddress.Index].Data;
                bool isDeleted = rowAddress.Page[rowAddress.Index].IsDeleted;
                LockFreeSync.ReadBarrier();
                // check if the row is still of the latest version
                if (rowAddress.Page[rowAddress.Index].LogIndex < logSize)
                {
                    // if it is still latest return.
                    if (isDeleted)
                    {
                        data = default;
                        throw new ArgumentOutOfRangeException(nameof(rowId));
                    }
                    return;
                }
            }
            // older version of the row requested. The data is in the log. Log is immutable so easy to read.
            ValueList <Log> .Address logAddress = this.log.ItemAddress(rowAddress.Page[rowAddress.Index].LogIndex);
            while (logSize <= logAddress.Page[logAddress.Index].LogIndex)
            {
                Debug.Assert(0 < logAddress.Page[logAddress.Index].LogIndex, "Log entry at 0 does not contain any real data and used as a stub");
                logAddress = this.log.ItemAddress(logAddress.Page[logAddress.Index].LogIndex);
            }
            if (logAddress.Page[logAddress.Index].IsDeleted)
            {
                data = default;
                throw new ArgumentOutOfRangeException(nameof(rowId));
            }
            data = logAddress.Page[logAddress.Index].Data;
        }
        /// <summary>
        /// Adds new element assuming enough memory for it already exist. This method should be prepared by PrepareAdd call.
        /// </summary>
        /// <param name="row"></param>
        /// <returns></returns>
        public int FixedAdd(ref TRow row)
        {
            int index = this.Count;
            //if(index == int.MaxValue) {
            //    throw new OverflowException();
            //}
            int pageIndex = index >> LogPageSize;
            int itemIndex = index & IndexOnPageMask;

            this.page[pageIndex][itemIndex] = row;
            LockFreeSync.WriteBarrier();
            this.Count++;
            return(index);
        }
Beispiel #5
0
 /// <summary>
 /// Reverts current transaction
 /// </summary>
 public void Rollback()
 {
     this.ValidateModification();
     RuntimeHelpers.PrepareConstrainedRegions();
     try { } finally {
         foreach (ISnapTable snapTable in this.Tables)
         {
             snapTable.Rollback();
         }
         ValueList <TransactionType> .Address address = this.version.ItemAddress(this.version.Count - 1);
         address.Page[address.Index] = TransactionType.Omit;
         this.CompletedVersion       = this.Version;
         this.editorThread           = null;
         this.editor = null;
         LockFreeSync.WriteBarrier();
     }
 }
        /// <summary>
        /// Ensures memory is allocated to accommodate for one more element
        /// </summary>
        public void PrepareAdd()
        {
            int index = this.Count;

            if (int.MaxValue - 1 <= index)
            {
                throw new InvalidOperationException(Properties.Resources.ErrorValueListTooBig);
            }
            int pageIndex = index >> LogPageSize;

            if (pageIndex == this.page.Length)
            {
                TRow[][] p = this.page;
                Array.Resize <TRow[]>(ref p, p.Length * 2);
                LockFreeSync.WriteBarrier();
                this.page = p;
            }
            int itemIndex = index & IndexOnPageMask;

            if (itemIndex == 0 && this.page[pageIndex] == null)
            {
                this.page[pageIndex] = new TRow[PageSize];
            }
        }