/// <summary> /// Append an object to the journal wrapped with a JournalEntry /// </summary> /// <returns>The id of the entry appended</returns> public ulong Append(Command item) { var entry = new JournalEntry <Command>(_nextEntryId, item, item.Timestamp); _writer.Write(entry); return(_nextEntryId++); }
/// <summary> /// Append an object to the journal wrapped with a JournalEntry /// </summary> /// <returns>The id of the entry appended</returns> public ulong Append(Command item) { var ts = Execution.Current.Now; var entry = new JournalEntry <Command>(_nextEntryId, item, ts); _writer.Write(entry); return(_nextEntryId++); }
/// <summary> /// Write a buffer of transactions (from lazy, usually) to the file /// </summary> public void Write(long posBy4Kb, byte *p, int numberOf4Kbs) { int posBy4Kbs = 0; while (posBy4Kbs < numberOf4Kbs) { var readTxHeader = (TransactionHeader *)(p + (posBy4Kbs * 4 * Constants.Size.Kilobyte)); var totalSize = readTxHeader->CompressedSize != -1 ? readTxHeader->CompressedSize + sizeof(TransactionHeader) : readTxHeader->UncompressedSize + sizeof(TransactionHeader); var roundTo4Kb = (totalSize / (4 * Constants.Size.Kilobyte)) + (totalSize % (4 * Constants.Size.Kilobyte) == 0 ? 0 : 1); if (roundTo4Kb > int.MaxValue) { MathFailure(numberOf4Kbs); } // We skip to the next transaction header. posBy4Kbs += (int)roundTo4Kb; Debug.Assert(readTxHeader->HeaderMarker == Constants.TransactionHeaderMarker); _transactionHeaders.Add(*readTxHeader); } JournalWriter.Write(posBy4Kb, p, numberOf4Kbs); }
/// <summary> /// Write a buffer of transactions (from lazy, usually) to the file /// </summary> public void Write(long posBy4Kb, byte *p, int numberOf4Kbs) { int posBy4Kbs = 0; while (posBy4Kbs < numberOf4Kbs) { var readTxHeader = (TransactionHeader *)(p + (posBy4Kbs * 4 * Constants.Size.Kilobyte)); var totalSize = readTxHeader->CompressedSize != -1 ? readTxHeader->CompressedSize + sizeof(TransactionHeader) : readTxHeader->UncompressedSize + sizeof(TransactionHeader); var roundTo4Kb = (totalSize / (4 * Constants.Size.Kilobyte)) + (totalSize % (4 * Constants.Size.Kilobyte) == 0 ? 0 : 1); if (roundTo4Kb > int.MaxValue) { MathFailure(numberOf4Kbs); } // We skip to the next transaction header. posBy4Kbs += (int)roundTo4Kb; if (_transactionHeaders.Length == _numberOfTransactionHeaders) { var temp = ArrayPool <TransactionHeader> .Shared.Rent(_transactionHeaders.Length * 2); Array.Copy(_transactionHeaders, temp, _transactionHeaders.Length); ArrayPool <TransactionHeader> .Shared.Return(_transactionHeaders); _transactionHeaders = temp; } Debug.Assert(readTxHeader->HeaderMarker == Constants.TransactionHeaderMarker); _transactionHeaders[_numberOfTransactionHeaders++] = *readTxHeader; } JournalWriter.Write(posBy4Kb, p, numberOf4Kbs); }
void WriteBackground() { _closeWaitHandle.Reset(); while (!_queue.IsCompleted) { JournalEntry item; if (_queue.TryTake(out item, Timeout.Infinite)) { _decoratedWriter.Write(item); } } _closeWaitHandle.Set(); }
/// <summary> /// write transaction's raw page data into journal /// </summary> public void Write(LowLevelTransaction tx, CompressedPagesResult pages, LazyTransactionBuffer lazyTransactionScratch) { var ptt = new Dictionary <long, PagePosition>(NumericEqualityComparer.BoxedInstanceInt64); var cur4KbPos = _writePosIn4Kb; Debug.Assert(pages.NumberOf4Kbs > 0); UpdatePageTranslationTable(tx, _unusedPagesHashSetPool, ptt); using (_locker2.Lock()) { Debug.Assert(!_unusedPages.Any(_unusedPagesHashSetPool.Contains)); // We ensure there cannot be duplicates here (disjoint sets). foreach (var item in _unusedPagesHashSetPool) { _unusedPages.Add(item); } } _unusedPagesHashSetPool.Clear(); if (tx.IsLazyTransaction == false && (lazyTransactionScratch == null || lazyTransactionScratch.HasDataInBuffer() == false)) { try { _journalWriter.Write(cur4KbPos, pages.Base, pages.NumberOf4Kbs); } catch (Exception e) { _env.Options.SetCatastrophicFailure(ExceptionDispatchInfo.Capture(e)); throw; } } else { if (lazyTransactionScratch == null) { throw new InvalidOperationException("lazyTransactionScratch cannot be null if the transaction is lazy (or a previous one was)"); } lazyTransactionScratch.EnsureSize(_journalWriter.NumberOfAllocated4Kb); lazyTransactionScratch.AddToBuffer(cur4KbPos, pages); // non lazy tx will add itself to the buffer and then flush scratch to journal if (tx.IsLazyTransaction == false || lazyTransactionScratch.NumberOfPages > tx.Environment.ScratchBufferPool.GetAvailablePagesCount() / 2) { try { lazyTransactionScratch.WriteBufferToFile(this, tx); } catch (Exception e) { _env.Options.SetCatastrophicFailure(ExceptionDispatchInfo.Capture(e)); throw; } } else { lazyTransactionScratch.EnsureHasExistingReadTransaction(tx); } } using (_locker2.Lock()) { _pageTranslationTable.SetItems(tx, ptt); // it is important that the last write position will be set // _after_ the PTT update, because a flush that is concurrent // with the write will first get the WritePosIn4KB and then // do the flush based on the PTT. Worst case, we'll flush // more then we need, but won't get into a position where we // think we flushed, and then realize that we didn't. Interlocked.Add(ref _writePosIn4Kb, pages.NumberOf4Kbs); } }
/// <summary> /// write transaction's raw page data into journal /// </summary> public void Write(LowLevelTransaction tx, CompressedPagesResult pages, LazyTransactionBuffer lazyTransactionScratch) { var ptt = new Dictionary <long, PagePosition>(NumericEqualityComparer.Instance); var cur4KbPos = _writePosIn4Kb; Debug.Assert(pages.NumberOf4Kbs > 0); UpdatePageTranslationTable(tx, _unusedPagesHashSetPool, ptt); using (_locker2.Lock()) { _writePosIn4Kb += pages.NumberOf4Kbs; Debug.Assert(!_unusedPages.Any(_unusedPagesHashSetPool.Contains)); // We ensure there cannot be duplicates here (disjoint sets). foreach (var item in _unusedPagesHashSetPool) { _unusedPages.Add(item); } } _unusedPagesHashSetPool.Clear(); if (tx.IsLazyTransaction == false && (lazyTransactionScratch == null || lazyTransactionScratch.HasDataInBuffer() == false)) { try { _journalWriter.Write(cur4KbPos, pages.Base, pages.NumberOf4Kbs); } catch (Exception e) { _env.Options.SetCatastrophicFailure(ExceptionDispatchInfo.Capture(e)); throw; } } else { if (lazyTransactionScratch == null) { throw new InvalidOperationException("lazyTransactionScratch cannot be null if the transaction is lazy (or a previous one was)"); } lazyTransactionScratch.EnsureSize(_journalWriter.NumberOfAllocated4Kb); lazyTransactionScratch.AddToBuffer(cur4KbPos, pages); // non lazy tx will add itself to the buffer and then flush scratch to journal if (tx.IsLazyTransaction == false || lazyTransactionScratch.NumberOfPages > tx.Environment.ScratchBufferPool.GetAvailablePagesCount() / 2) { try { lazyTransactionScratch.WriteBufferToFile(this, tx); } catch (Exception e) { _env.Options.SetCatastrophicFailure(ExceptionDispatchInfo.Capture(e)); throw; } } else { lazyTransactionScratch.EnsureHasExistingReadTransaction(tx); } } using (_locker2.Lock()) { _pageTranslationTable.SetItems(tx, ptt); } }