Exemple #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 (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 (stream is FileStream)
                    {
                        NativeLockFile.UnlockFile((FileStream)stream, indexStreamPosition, long.MaxValue - indexStreamPosition);
                    }
                }
            }
        }
Exemple #2
0
        private void LockFile(long offset, long count, bool exclusive)
        {
#if !XENKO_PLATFORM_UWP
            var fileStream = stream as FileStream;
            if (fileStream == null)
            {
                return;
            }

#if XENKO_PLATFORM_ANDROID
            // Android does not support large file and thus is limited to files
            // whose sizes are less than 2GB.
            // We substract the offset to not go beyond the 2GB limit.
            count = (count + offset > int.MaxValue) ? int.MaxValue - offset: count;
#endif

#if XENKO_PLATFORM_WINDOWS_DESKTOP
            var countLow  = (uint)count;
            var countHigh = (uint)(count >> 32);

            var overlapped = new NativeOverlapped()
            {
                InternalLow  = IntPtr.Zero,
                InternalHigh = IntPtr.Zero,
                OffsetLow    = (int)(offset & 0x00000000FFFFFFFF),
                OffsetHigh   = (int)(offset >> 32),
                EventHandle  = IntPtr.Zero,
            };

            if (!NativeLockFile.LockFileEx(fileStream.SafeFileHandle, exclusive ? NativeLockFile.LOCKFILE_EXCLUSIVE_LOCK : 0, 0, countLow, countHigh, ref overlapped))
            {
                throw new IOException("Couldn't lock file.");
            }
#elif XENKO_RUNTIME_CORECLR
            // There is no implementation of FileStream.Lock on CoreCLR
#else
            bool tryAgain;
            do
            {
                tryAgain = false;
                try
                {
                    fileStream.Lock(offset, count);
                }
                catch (IOException)
                {
                    tryAgain = true;
                }
            } while (tryAgain);
#endif
#endif
        }
Exemple #3
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 (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 (stream is FileStream)
                    {
                        NativeLockFile.UnlockFile((FileStream)stream, position, long.MaxValue - position);
                    }
                }

                return(true);
            }
        }
Exemple #4
0
        private void UnlockFile(long offset, long count)
        {
#if !XENKO_PLATFORM_UWP
            var fileStream = stream as FileStream;
            if (fileStream == null)
            {
                return;
            }

#if XENKO_PLATFORM_ANDROID
            // See comment on `LockFile`.
            count = (count + offset > int.MaxValue) ? int.MaxValue - offset: count;
#endif

#if XENKO_PLATFORM_WINDOWS_DESKTOP
            var countLow  = (uint)count;
            var countHigh = (uint)(count >> 32);

            var overlapped = new NativeOverlapped()
            {
                InternalLow  = IntPtr.Zero,
                InternalHigh = IntPtr.Zero,
                OffsetLow    = (int)(offset & 0x00000000FFFFFFFF),
                OffsetHigh   = (int)(offset >> 32),
                EventHandle  = IntPtr.Zero,
            };

            if (!NativeLockFile.UnlockFileEx(fileStream.SafeFileHandle, 0, countLow, countHigh, ref overlapped))
            {
                throw new IOException("Couldn't unlock file.");
            }
#elif XENKO_RUNTIME_CORECLR
            // There is no implementation of FileStream.Unlock on CoreCLR
#else
            fileStream.Unlock(offset, count);
#endif
#endif
        }