| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- //------------------------------------------------------------------------------
- // <copyright file="RecordManager.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- // <owner current="true" primary="true">[....]</owner>
- // <owner current="true" primary="false">[....]</owner>
- //------------------------------------------------------------------------------
- namespace System.Data {
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- internal sealed class RecordManager {
- private readonly DataTable table;
- private int lastFreeRecord;
- private int minimumCapacity = 50;
- private int recordCapacity = 0;
- private readonly List<int> freeRecordList = new List<int>();
- DataRow[] rows;
- internal RecordManager(DataTable table) {
- if (table == null) {
- throw ExceptionBuilder.ArgumentNull("table");
- }
- this.table = table;
- }
- private void GrowRecordCapacity() {
- if (NewCapacity(recordCapacity) < NormalizedMinimumCapacity(minimumCapacity))
- RecordCapacity = NormalizedMinimumCapacity(minimumCapacity);
- else
- RecordCapacity = NewCapacity(recordCapacity);
- // set up internal map : record --> row
- DataRow[] newRows = table.NewRowArray(recordCapacity);
- if (rows != null) {
- Array.Copy(rows, 0, newRows, 0, Math.Min(lastFreeRecord, rows.Length));
- }
- rows = newRows;
- }
- internal int LastFreeRecord {
- get { return lastFreeRecord; }
- }
- internal int MinimumCapacity {
- get {
- return minimumCapacity;
- }
- set {
- if (minimumCapacity != value) {
- if (value < 0) {
- throw ExceptionBuilder.NegativeMinimumCapacity();
- }
- minimumCapacity = value;
- }
- }
- }
- internal int RecordCapacity {
- get {
- return recordCapacity;
- }
- set {
- if (recordCapacity != value) {
- for (int i = 0; i < table.Columns.Count; i++) {
- table.Columns[i].SetCapacity(value);
- }
- recordCapacity = value;
- }
- }
- }
- internal static int NewCapacity(int capacity) {
- return (capacity < 128) ? 128 : (capacity + capacity);
- }
- // Normalization: 64, 256, 1024, 2k, 3k, ....
- private int NormalizedMinimumCapacity(int capacity) {
- if (capacity < 1024 - 10) {
- if (capacity < 256 - 10) {
- if ( capacity < 54 )
- return 64;
- return 256;
- }
- return 1024;
- }
- return (((capacity + 10) >> 10) + 1) << 10;
- }
- internal int NewRecordBase() {
- int record;
- if (freeRecordList.Count != 0) {
- record = freeRecordList[freeRecordList.Count - 1];
- freeRecordList.RemoveAt(freeRecordList.Count - 1);
- }
- else {
- if (lastFreeRecord >= recordCapacity) {
- GrowRecordCapacity();
- }
- record = lastFreeRecord;
- lastFreeRecord++;
- }
- Debug.Assert(record >=0 && record < recordCapacity, "NewRecord: Invalid record");
- return record;
- }
- internal void FreeRecord(ref int record) {
- Debug.Assert(-1 <= record && record < recordCapacity, "invalid record");
- // Debug.Assert(record < lastFreeRecord, "Attempt to Free() <outofbounds> record");
- if (-1 != record) {
- this[record] = null;
- int count = table.columnCollection.Count;
- for(int i = 0; i < count; ++i) {
- table.columnCollection[i].FreeRecord(record);
- }
- // if freeing the last record, recycle it
- if (lastFreeRecord == record + 1) {
- lastFreeRecord--;
- }
- else if (record < lastFreeRecord) {
- // Debug.Assert(-1 == freeRecordList.IndexOf(record), "Attempt to double Free() record");
- freeRecordList.Add(record);
- }
- record = -1;
- }
- }
- internal void Clear(bool clearAll) {
- if (clearAll) {
- for(int record = 0; record < recordCapacity; ++record) {
- rows[record] = null;
- }
- int count = table.columnCollection.Count;
- for(int i = 0; i < count; ++i) {
- // SQLBU 415729: Serious performance issue when calling Clear()
- // this improves performance by caching the column instead of obtaining it for each row
- DataColumn column = table.columnCollection[i];
- for(int record = 0; record < recordCapacity; ++record) {
- column.FreeRecord(record);
- }
- }
- lastFreeRecord = 0;
- freeRecordList.Clear();
- }
- else { // just clear attached rows
- freeRecordList.Capacity = freeRecordList.Count + table.Rows.Count;
- for(int record = 0; record < recordCapacity; ++record) {
- if (rows[record]!= null && rows[record].rowID != -1) {
- int tempRecord = record;
- FreeRecord(ref tempRecord);
- }
- }
- }
- }
-
- internal DataRow this[int record] {
- get {
- Debug.Assert(record >= 0 && record < rows.Length, "Invalid record number");
- return rows[record];
- }
- set {
- Debug.Assert(record >= 0 && record < rows.Length, "Invalid record number");
- rows[record] = value;
- }
- }
- internal void SetKeyValues(int record, DataKey key, object[] keyValues) {
- for (int i = 0; i < keyValues.Length; i++) {
- key.ColumnsReference[i][record] = keyValues[i];
- }
- }
- // Increases AutoIncrementCurrent
- internal int ImportRecord(DataTable src, int record) {
- return CopyRecord(src, record, -1);
- }
- // No impact on AutoIncrementCurrent if over written
- internal int CopyRecord(DataTable src, int record, int copy) {
- Debug.Assert(src != null, "Can not Merge record without a table");
-
- if (record == -1) {
- return copy;
- }
- int newRecord = -1;
- try {
- if (copy == -1) {
- newRecord = table.NewUninitializedRecord();
- }
- else {
- newRecord = copy;
- }
- int count = table.Columns.Count;
- for (int i = 0; i < count; ++i) {
- DataColumn dstColumn = table.Columns[i];
- DataColumn srcColumn = src.Columns[dstColumn.ColumnName];
- if (null != srcColumn) {
- object value = srcColumn[record];
- ICloneable cloneableObject = value as ICloneable;
- if (null != cloneableObject) {
- dstColumn[newRecord] = cloneableObject.Clone();
- }
- else {
- dstColumn[newRecord] = value;
- }
- }
- else if (-1 == copy) {
- dstColumn.Init(newRecord);
- }
- }
- }
- catch (Exception e){
- //
- if (Common.ADP.IsCatchableOrSecurityExceptionType(e)) {
- if (-1 == copy) {
- FreeRecord(ref newRecord);
- }
- }
- throw;
- }
- return newRecord;
- }
- internal void SetRowCache(DataRow[] newRows) {
- rows = newRows;
- lastFreeRecord = rows.Length;
- recordCapacity = lastFreeRecord;
- }
- [Conditional("DEBUG")]
- internal void VerifyRecord(int record) {
- Debug.Assert((record < lastFreeRecord) && (-1 == freeRecordList.IndexOf(record)), "accesing free record");
- Debug.Assert((null == rows[record]) ||
- (record == rows[record].oldRecord) ||
- (record == rows[record].newRecord) ||
- (record == rows[record].tempRecord), "record of a different row");
- }
- [Conditional("DEBUG")]
- internal void VerifyRecord(int record, DataRow row) {
- Debug.Assert((record < lastFreeRecord) && (-1 == freeRecordList.IndexOf(record)), "accesing free record");
- Debug.Assert((null == rows[record]) || (row == rows[record]), "record of a different row");
- }
- }
- }
|