Ejemplo n.º 1
0
        /// <summary>
        /// Try enter in shared lock (read) - Call action if request a new lock
        /// [Non ThreadSafe]
        /// </summary>
        private Action LockShared()
        {
            lock (_disk)
            {
                if (_state != LockState.Unlocked)
                {
                    return () => { }
                }
                ;

                _disk.Lock(LockState.Shared, _timeout);

                _state  = LockState.Shared;
                _shared = true;

                _log.Write(LoggerWrap.LOCK, "entered in shared lock mode");

                this.AvoidDirtyRead();

                return(() =>
                {
                    _shared = false;
                    _disk.Unlock(LockState.Shared);
                    _state = LockState.Unlocked;

                    _log.Write(LoggerWrap.LOCK, "exited shared lock mode");
                });
            }
        }
Ejemplo n.º 2
0
        public void Initialize(LoggerWrap log, string password)
        {
            // get log instance to disk
            _log = log;

            // if is read only, journal must be disabled
            if (_options.FileMode == FileMode.ReadOnly)
            {
                _options.Journal = false;
            }

            // open/create file using read only/exclusive options
            _stream = CreateFileStream(_filename,
                                       _options.FileMode == FileMode.ReadOnly ? System.IO.FileMode.Open : System.IO.FileMode.OpenOrCreate,
                                       _options.FileMode == FileMode.ReadOnly ? FileAccess.Read : FileAccess.ReadWrite,
                                       _options.FileMode == FileMode.Exclusive ? FileShare.None : FileShare.ReadWrite);

            // if file is new, initialize
            if (_stream.Length == 0)
            {
                _log.Write(LoggerWrap.DISK, "initialize new datafile");

                // set datafile initial size
                _stream.SetLength(_options.InitialSize);

                // create datafile
                LiteEngine.CreateDatabase(_stream, password);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Read page bytes from disk
        /// </summary>
        public virtual byte[] ReadPage(uint pageID)
        {
            var buffer   = new byte[BasePage.PAGE_SIZE];
            var position = BasePage.GetSizeOfPages(pageID);

            // position cursor
            if (_stream.Position != position)
            {
                _stream.Seek(position, SeekOrigin.Begin);
            }

            // read bytes from data file
            _stream.Read(buffer, 0, BasePage.PAGE_SIZE);

            _log.Write(LoggerWrap.DISK, "read page #{0:0000} :: {1}", pageID, (PageType)buffer[PAGE_TYPE_POSITION]);

            return(buffer);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Try recovery journal file (if exists). Restore original datafile
        /// Journal file are NOT encrypted (even when datafile are encrypted)
        /// </summary>
        public void Recovery()
        {
            var fileSize = _disk.FileLength;
            var pages    = 0;

            // read all journal pages
            foreach (var buffer in _disk.ReadJournal())
            {
                // read pageID (first 4 bytes)
                var pageID = BitConverter.ToUInt32(buffer, 0);

                _log.Write(LoggerWrap.RECOVERY, "recover page #{0:0000}", pageID);

                // if header, read all byte (to get original filesize)
                if (pageID == 0)
                {
                    var header = (HeaderPage)BasePage.ReadPage(buffer);

                    fileSize = BasePage.GetSizeOfPages(header.LastPageID + 1);
                }

                // write in stream (encrypt if datafile is encrypted)
                _disk.WritePage(pageID, _crypto == null || pageID == 0 ? buffer : _crypto.Encrypt(buffer));

                pages++;
            }

            // no pages, no recovery
            if (pages == 0)
            {
                return;
            }

            _log.Write(LoggerWrap.RECOVERY, "resize datafile to {0} bytes", fileSize);

            // redim filesize if grow more than original before rollback
            _disk.SetLength(fileSize);

            // empty journal file
            _disk.ClearJournal();
        }
Ejemplo n.º 5
0
        public void Initialize(LoggerWrap log, string password)
        {
            // get log instance to disk
            _log = log;

            // if stream are empty, create header page and save to stream
            if (_stream.Length == 0)
            {
                _log.Write(LoggerWrap.DISK, "initialize new datafile");

                // create datafile
                LiteEngine.CreateDatabase(_stream, password);
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Get the collection page only when needed. Gets from pager always to grantee that wil be the last (in case of clear cache will get a new one - pageID never changes)
        /// </summary>
        private CollectionPage GetCollectionPage(string name, bool addIfNotExits)
        {
            if (name == null)
            {
                return(null);
            }

            // search my page on collection service
            var col = _collections.Get(name);

            if (col == null && addIfNotExits)
            {
                _log.Write(LoggerWrap.COMMAND, "create new collection '{0}'", name);

                col = _collections.Add(name);
            }

            return(col);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Add a new collection. Check if name the not exists
        /// </summary>
        public CollectionPage Add(string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("name");
            }
            if (!CollectionPage.NamePattern.IsMatch(name))
            {
                throw LiteException.InvalidFormat("Collection", name);
            }

            _log.Write(LoggerWrap.COMMAND, "creating new collection '{0}'", name);

            // get header marked as dirty because I will use header after (and NewPage can get another header instance)
            var header = _pager.GetPage <HeaderPage>(0);

            // check limit count (8 bytes per collection = 4 to string length, 4 for uint pageID)
            if (header.CollectionPages.Sum(x => x.Key.Length + 8) + name.Length + 8 >= CollectionPage.MAX_COLLECTIONS_SIZE)
            {
                throw LiteException.CollectionLimitExceeded(CollectionPage.MAX_COLLECTIONS_SIZE);
            }

            // get new collection page (marked as dirty)
            var col = _pager.NewPage <CollectionPage>();

            // add this page to header page collection
            header.CollectionPages.Add(name, col.PageID);

            col.CollectionName = name;

            // set header page as dirty
            _pager.SetDirty(header);

            // create PK index
            var pk = _indexer.CreateIndex(col);

            pk.Field  = "_id";
            pk.Unique = true;

            return(col);
        }
Ejemplo n.º 8
0
 public virtual void Dispose()
 {
     if (_journal != null)
     {
         _log.Write(LoggerWrap.DISK, "close journal file '{0}'", Path.GetFileName(_journalFilename));
         _journal.Dispose();
         _journal = null;
         FileHelper.TryDelete(_journalFilename);
     }
     if (_stream != null)
     {
         _log.Write(LoggerWrap.DISK, "close datafile '{0}'", Path.GetFileName(_filename));
         _stream.Dispose();
         _stream = null;
     }
 }
Ejemplo n.º 9
0
        /// <summary>
        /// Discard only dirty pages
        /// [ThreadSafe]
        /// </summary>
        public void DiscardDirtyPages()
        {
            _log.Write(LoggerWrap.CACHE, "clearing dirty pages from cache");

            _dirty.Clear();
        }