Click here to Skip to main content
15,891,372 members
Articles / Programming Languages / C#

Building an embedded database engine in C#

Rate me:
Please Sign up or sign in to vote.
4.91/5 (110 votes)
10 Jun 2009CPOL8 min read 321.6K   10K   347  
DbfDotNet is a very fast and compact fully managed standalone database/entity framework, for the .Net Framework.
using System;
using System.Collections.Generic;
using System.Text;

namespace DbfDotNet.Core
{
    internal class RecordHolder
    {
        internal ClusteredFile mFile;
        private readonly UInt32 mRecordNo;
        private WeakReference mRecordWeakRef;
        private byte[] mReadBuffer;
        private byte[] mWriteBuffer;
        internal System.Threading.EventWaitHandle RecordFinalized;

        private object mHold;

        public RecordHolder(ClusteredFile file, UInt32 RecordNo, Record record)
        {
            RecordFinalized = new System.Threading.EventWaitHandle(false, 
                System.Threading.EventResetMode.ManualReset);
#if DUMP_FINALIZE
            System.Diagnostics.Trace.WriteLine(file.mOriginalFile + " New RecordHolder for #" + RecordNo);
            System.Diagnostics.Debug.Assert(record != null);
#endif

            mFile = file;
            mRecordNo = RecordNo;
            MakeWeakRef(record);
            mHold = record;
        }

        public UInt32 RecordNo
        {
            get { return mRecordNo; }
        }

        public bool Hold
        {
            get { return mHold != null; }
            set { mHold = (value ? Record : null); }
        }

        private void MakeWeakRef(Record record)
        {
            mRecordWeakRef = new WeakReference(record, false);
        }

        public Record Record
        {
            get
            {
                if (mRecordWeakRef == null) return null;
                var result = mRecordWeakRef.Target as Record;
                return result;
            }
            set
            {
                // We could be tempted to write
                // mRecordWeakRef.Target=value 
                // but this is not advisable as this property
                // could be call from a GC destructor.
                MakeWeakRef(value);
            }
        }
     
        internal void OnRecordFinalizing(Record record)
        {
            try
            {
                // first we write the buffer 
                mFile.InternalFillWriteBuffer(this, record);
            }
            finally
            {
                // This is one of the only place where we use Threading mechanism.
                // The mainthread might be waiting for it
                RecordFinalized.Set();
            }
        }

        internal byte[] GetCurrentBuffer(bool readIfNeeded)
        {
            if (mWriteBuffer!=null) return mWriteBuffer;
            if (mReadBuffer!=null) return mReadBuffer;

            if (readIfNeeded)
            {
                mReadBuffer = new byte[mFile.mRecordWidth];
                mFile.InternalReadRecordFromDisk(mRecordNo, mReadBuffer);
                return mReadBuffer;
            }
            else return null;
        }

        internal bool IsModified()
        {
            return (mWriteBuffer != null);
        }

        internal void SetNewBuffer(Byte[] newBuffer)
        {
            bool modified = false;
            if (mReadBuffer == null) modified = true;
            else
            {
                int len = mFile.mRecordWidth;
                for (int i = 0; i < len; i++)
                {
                    if (mReadBuffer[i] != newBuffer[i])
                    {
                        modified = true;
                        break;
                    }
                }
            }
            if (modified)
            {
                var currentBuffer = (mWriteBuffer != null ? mWriteBuffer : mReadBuffer);
                // we could clear the readBuffer here to save memory
                mFile.OnWriteBufferModified(mRecordNo, currentBuffer, newBuffer);
                mWriteBuffer = newBuffer;
            }

        }

        internal void Save()
        {
            if (mWriteBuffer != null)
            {
                mFile.InternalSaveRecordToDisk(mRecordNo, mWriteBuffer);
                mWriteBuffer = null;
            }
        }

        internal void SaveChanges(Record record)
        {
            mFile.InternalFillWriteBuffer(this, record);
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
France France
I am a French programmer.
These days I spend most of my time with the .NET framework, JavaScript and html.

Comments and Discussions