4 using System.Collections.Generic;
6 using System.Runtime.InteropServices;
7 using System.Threading.Tasks;
8 using SiliconStudio.Core.Serialization;
10 #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP
11 using Microsoft.Win32.SafeHandles;
14 namespace SiliconStudio.Core.IO
18 #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP
19 [StructLayout(LayoutKind.Sequential)]
20 public struct OVERLAPPED
22 public uint internalLow;
23 public uint internalHigh;
24 public uint offsetLow;
25 public uint offsetHigh;
29 [DllImport(
"Kernel32.dll", SetLastError =
true)]
30 public static extern bool LockFileEx(SafeFileHandle handle, uint
flags, uint reserved, uint countLow, uint countHigh, ref OVERLAPPED overlapped);
32 [DllImport(
"Kernel32.dll", SetLastError =
true)]
33 public static extern bool UnlockFileEx(SafeFileHandle handle, uint reserved, uint countLow, uint countHigh, ref OVERLAPPED overlapped);
35 public const uint LOCKFILE_EXCLUSIVE_LOCK = 0x00000002;
44 public abstract class Store<T> : IDisposable where T : new()
49 protected object lockObject =
new object();
54 public bool UseTransaction {
get; set; }
59 public bool AutoLoadNewValues {
get; set; }
63 AutoLoadNewValues =
true;
92 var useTransaction = UseTransaction;
93 int currentTransaction = transaction;
97 foreach (var value
in values)
100 AddUnsaved(value, currentTransaction);
105 SaveValues(values, currentTransaction);
119 var useTransaction = UseTransaction;
120 int currentTransaction = transaction;
125 AddUnsaved(item, currentTransaction);
129 SaveValue(item, currentTransaction);
134 private void SaveValues(
IEnumerable<T> values,
int currentTransaction)
137 throw new InvalidOperationException(
"No active stream.");
141 var indexStreamPosition = stream.Position;
145 LockFile(indexStreamPosition,
long.MaxValue,
true);
150 if (AutoLoadNewValues)
151 RefreshData(stream.Length);
153 stream.Position = stream.Length;
155 foreach (var value
in values)
157 WriteEntry(stream, value);
164 RemoveUnsaved(values, currentTransaction);
165 foreach (var value
in values)
173 UnlockFile(indexStreamPosition,
long.MaxValue);
178 private void SaveValue(T item,
int currentTransaction)
181 throw new InvalidOperationException(
"No active stream.");
185 var indexStreamPosition = stream.Position;
189 LockFile(indexStreamPosition,
long.MaxValue,
true);
194 if (AutoLoadNewValues)
195 RefreshData(stream.Length);
197 stream.Position = stream.Length;
199 WriteEntry(stream, item);
205 RemoveUnsaved(item, currentTransaction);
211 UnlockFile(indexStreamPosition,
long.MaxValue);
224 int currentTransaction = transaction++;
225 var transactionIds = GetPendingItems(currentTransaction);
227 SaveValues(transactionIds, currentTransaction);
263 throw new InvalidOperationException(
"No active stream.");
267 var position = stream.Position;
268 var fileSize = stream.Length;
270 if (position == fileSize)
279 #if !SILICONSTUDIO_PLATFORM_WINDOWS_RUNTIME
280 if (stream is FileStream)
281 LockFile(position,
long.MaxValue,
false);
287 fileSize = stream.Length;
288 RefreshData(fileSize);
292 #if !SILICONSTUDIO_PLATFORM_WINDOWS_RUNTIME
294 if (stream is FileStream)
295 UnlockFile(position,
long.MaxValue);
303 private void LockFile(
long offset,
long count,
bool exclusive)
305 #if !SILICONSTUDIO_PLATFORM_WINDOWS_RUNTIME && !SILICONSTUDIO_PLATFORM_MONO_MOBILE
306 var fileStream = (FileStream)stream;
308 #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP
309 var countLow = (uint)count;
310 var countHigh = (uint)(count >> 32);
312 var overlapped =
new Store.OVERLAPPED()
316 offsetLow = (uint)offset,
317 offsetHigh = (uint)(offset >> 32),
318 hEvent = IntPtr.Zero,
321 if (!Store.LockFileEx(fileStream.SafeFileHandle, exclusive ? Store.LOCKFILE_EXCLUSIVE_LOCK : 0, 0, countLow, countHigh, ref overlapped))
323 throw new IOException(
"Couldn't lock file.");
332 fileStream.Lock(offset,
count);
343 private void UnlockFile(
long offset,
long count)
345 #if !SILICONSTUDIO_PLATFORM_WINDOWS_RUNTIME && !SILICONSTUDIO_PLATFORM_MONO_MOBILE
346 var fileStream = (FileStream)stream;
348 #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP
349 var countLow = (uint)count;
350 var countHigh = (uint)(count >> 32);
352 var overlapped =
new Store.OVERLAPPED()
356 offsetLow = (uint)offset,
357 offsetHigh = (uint)(offset >> 32),
358 hEvent = IntPtr.Zero,
361 if (!
Store.UnlockFileEx(fileStream.SafeFileHandle, 0, countLow, countHigh, ref overlapped))
363 throw new IOException(
"Couldn't unlock file.");
366 fileStream.Unlock(offset,
count);
371 private void RefreshData(
long fileSize)
373 var streamBeginPosition = stream.Position;
376 var length = (int)(fileSize - stream.Position);
377 var bufferToRead =
new byte[length];
378 stream.Read(bufferToRead, 0, length);
379 var memoryStream =
new MemoryStream(bufferToRead);
383 var entries = ReadEntries(memoryStream);
387 foreach (var entry
in entries)
396 stream.Position = streamBeginPosition;
406 protected abstract void AddUnsaved(T item,
int transaction);
413 protected abstract void RemoveUnsaved(T item,
int transaction);
422 foreach (var item
in items)
424 RemoveUnsaved(item, transaction);
432 protected abstract void AddLoaded(T item);
439 protected abstract IEnumerable<T> GetPendingItems(
int transaction);
450 var entries =
new List<T>();
451 while (localStream.Position < localStream.Length)
454 reader.Serialize(ref entry, ArchiveMode.Deserialize);
463 reader.Serialize(ref value, ArchiveMode.Serialize);
virtual void WriteEntry(Stream stream, T value)
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ DXGI_FORMAT _In_ DWORD flags
virtual List< T > ReadEntries(Stream localStream)
Implements SerializationStream as a binary writer.
bool LoadNewValues()
Refreshes URL to ObjectId mapping from the latest results in the index file.
Implements SerializationStream as a binary reader.
void AddValue(T item)
Adds a value to the store.
void Reset()
Resets the store to an empty state.
void AddValues(IEnumerable< T > values)
Adds multiple values to the store
void Dispose()
Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resourc...
virtual void ResetInternal()
Resets the store to an empty state, to be implemented by subclasses if necessary. ...
virtual void RemoveUnsaved(IEnumerable< T > items, int transaction)
Removes values that have not yet been saved (pending state).
void Save()
Saves the newly added mapping (only necessary when UseTransaction is set to true).
virtual object BuildContext(Stream stream)