Example #1
0
        private void SaveValues(IEnumerable <T> values, int currentTransaction)
        {
            if (stream == null)
            {
                throw new InvalidOperationException("No active stream.");
            }

            lock (stream)
            {
                var indexStreamPosition = stream.Position;

                // Acquire lock on end of file (for appending)
                // This will prevent another thread from writing at the same time, or reading before it is flushed.
                if (LockEnabled && stream is FileStream)
                {
                    NativeLockFile.LockFile((FileStream)stream, indexStreamPosition, long.MaxValue - indexStreamPosition, true);
                }

                try
                {
                    // Make sure we read up entries up to end of file (or skip it if AutoLoadNewValues is not set)
                    if (AutoLoadNewValues)
                    {
                        RefreshData(stream.Length);
                    }
                    else
                    {
                        stream.Position = stream.Length;
                    }

                    foreach (var value in values)
                    {
                        WriteEntry(stream, value);
                    }
                    stream.Flush();

                    // Transfer from temporary mapping to real mapping (so that loadedIdMap is updated in right order)
                    lock (lockObject)
                    {
                        RemoveUnsaved(values, currentTransaction);
                        foreach (var value in values)
                        {
                            AddLoaded(value);
                        }
                    }
                }
                finally
                {
                    if (LockEnabled && stream is FileStream)
                    {
                        NativeLockFile.UnlockFile((FileStream)stream, indexStreamPosition, long.MaxValue - indexStreamPosition);
                    }
                }
            }
        }
Example #2
0
        /// <summary>
        /// Refreshes URL to ObjectId mapping from the latest results in the index file.
        /// </summary>
        /// <returns>True on success.</returns>
        public bool LoadNewValues()
        {
            if (stream == null)
            {
                throw new InvalidOperationException("No active stream.");
            }

            lock (stream)
            {
                var position = stream.Position;
                var fileSize = stream.Length;

                if (position == fileSize)
                {
                    return(true);
                }

                // Lock content that will be read.
                // This lock doesn't prevent concurrent writing since we lock only until current known filesize.
                // In the case where fileSize was taken at the time of an incomplete append, this lock will also wait for completion of the last write.
                // Note: Maybe we should release the lock quickly so that two threads can read at the same time?
                // Or if the previously described case doesn't happen, maybe no lock at all is required?
                // Otherwise, last possibility would be deterministic filesize (with size encoded at the beginning of each block).
                if (LockEnabled && stream is FileStream)
                {
                    NativeLockFile.LockFile((FileStream)stream, position, long.MaxValue - position, false);
                }

                try
                {
                    // update the size after the lock
                    fileSize = stream.Length;
                    RefreshData(fileSize);
                }
                finally
                {
                    // Release the lock
                    if (LockEnabled && stream is FileStream)
                    {
                        NativeLockFile.UnlockFile((FileStream)stream, position, long.MaxValue - position);
                    }
                }

                return(true);
            }
        }