private void ReadAllFromDisk()
		{
			file.Position = ReadOffsets(Path.GetFileName(streamSource.GetLatestName(dataPath)));
			while (true)
			{
				using (var reader = new BinaryReader(file, Encoding.UTF8, leaveOpen: true))
				{
					var itemPos = file.Position;
					PersistedEvent persistedEvent;
					try
					{
						persistedEvent = ReadPersistedEvent(reader);
						eventsCount++;
					}
					catch (EndOfStreamException)
					{
						lastWriteSnapshotCount = eventsCount;
						lastWriteSnapshotTime = DateTime.UtcNow;
						return;
					}
					catch (Exception e)
					{
						log.WarnException("Error during initial events read, file corrupted", e);
						if (options.AllowRecovery == false)
							throw;
						file.SetLength(itemPos);
						log.Warn("Recovered from corrupted file by truncating file to last known good position: " + itemPos);
						return;
					}
					switch (persistedEvent.State)
					{
						case EventState.Event:
						case EventState.Snapshot:
							idToPos.AddOrUpdate(persistedEvent.Id, s => new StreamInformation
								{
									LastPosition = itemPos,
									StreamLength = 1
								}, (s, information) => new StreamInformation
									{
										LastPosition = itemPos,
										StreamLength = information.StreamLength + 1
									});
							break;
						case EventState.Delete:
							deleteCount++;
							var streamInformation = new StreamInformation
								{
									LastPosition = Deleted,
									StreamLength = 0
								};
							idToPos.AddOrUpdate(persistedEvent.Id, s => streamInformation, (s, information) =>
								{
									deleteCount += information.StreamLength;
									return streamInformation;
								});
							break;
						default:
							throw new ArgumentOutOfRangeException(persistedEvent.State.ToString());
					}

				}
			}
		}
		private void HandleFlushSuccessful(WriteState item, long currentPos)
		{
			switch (item.State)
			{
				case EventState.Event:
				case EventState.Snapshot:
					idToPos.AddOrUpdate(item.Id, s => new StreamInformation
						{
							LastPosition = currentPos,
							StreamLength = 1
						}, (s, l) => new StreamInformation
							{
								LastPosition = currentPos,
								StreamLength = l.StreamLength + 1
							});
					break;
				case EventState.Delete:
					var streamInformation = new StreamInformation
						{
							LastPosition = Deleted,
							StreamLength = 0
						};
					idToPos.AddOrUpdate(item.Id, s => streamInformation, (s, l) =>
						{
							deleteCount += l.StreamLength;
							return streamInformation;
						});
					break;
				default:
					throw new ArgumentOutOfRangeException(item.State.ToString());
			}
			item.TaskCompletionSource.SetResult(null);
		}
		private long ReadOffsets(string currentFileName)
		{
			long position;
			if (streamSource.Exists(offsetsPath) == false)
				return 0;
			using (var offsets = streamSource.OpenRead(offsetsPath))
			using(var reader = new BinaryReader(offsets))
			{
				var fileName = reader.ReadString();
				if(fileName != currentFileName)
				{
					// wrong file, skipping
					streamSource.DeleteOnClose(offsetsPath);
					return 0;
				}
				position = reader.ReadInt64();

				while (true)
				{
					string key;
					try
					{
						key = reader.ReadString();
					}
					catch (EndOfStreamException)
					{
						break;
					}
					var pos = reader.ReadInt64();
					var count = reader.ReadInt32();

					idToPos[key] = new StreamInformation
						{
							LastPosition = pos,
							StreamLength = count
						};
				}
			}

			return position;
		}
		public void Compact()
		{
			var newPositions = new Dictionary<string, StreamInformation>(StringComparer.InvariantCultureIgnoreCase);

			var newFilePath = dataPath + ".compacting";
			streamSource.DeleteIfExists(newFilePath);

			using (var newFile = streamSource.OpenReadWrite(newFilePath))
			using (var newWriter = new BinaryWriter(newFile))
			using (var current = streamSource.OpenRead(dataPath))
			using (var reader = new BinaryReader(current))
			{
				while (true)
				{
					PersistedEvent persistedEvent;
					try
					{
						persistedEvent = ReadPersistedEvent(reader);
					}
					catch (EndOfStreamException)
					{
						break;
					}
					StreamInformation value;
					if (idToPos.TryGetValue(persistedEvent.Id, out value) == false)
						continue;


					if (value.LastPosition == Deleted || value.LastPosition == DoesNotExists)
						continue;

					StreamInformation information;
					if (newPositions.TryGetValue(persistedEvent.Id, out information) == false)
					{
						information =new StreamInformation
							{
								LastPosition = DoesNotExists,
								StreamLength = 0
							};
					}

					persistedEvent.Previous = information.LastPosition;

					newPositions[persistedEvent.Id] = new StreamInformation
						{
							LastPosition = newFile.Position,
							StreamLength = persistedEvent.StreamLength
						};
					WriteItem(persistedEvent, newWriter);
				}

				streamSource.Flush(newFile);

				compactionLock.EnterWriteLock();
				try
				{
					newFile.Close();
					streamSource.DeleteOnClose(dataPath);

					Stream result;
					while (cachedReadStreams.TryDequeue(out result))
					{
						result.Dispose();
					}

					binaryWriter.Dispose();
					file.Dispose();

					streamSource.RenameToLatest(newFilePath, dataPath);
					file = streamSource.OpenReadWrite(dataPath);
					binaryWriter = new BinaryWriter(file, Encoding.UTF8, leaveOpen: true);
					
					streamSource.DeleteIfExists("data.offsets");
					FlushOffsets();
					
					idToPos.Clear();
					foreach (var val in newPositions)
					{
						idToPos[val.Key] = val.Value;
					}
				}
				finally
				{
					compactionLock.ExitWriteLock();
				}

			}
		}