Skip to content

Commit

Permalink
Merge pull request #2481 from oleksii-datsiuk/odatsiuk/prevent-ensure…
Browse files Browse the repository at this point in the history
…-clear-cache-and-db-corruption

Prevent using disposed snapshots
  • Loading branch information
JKamsker authored Jun 4, 2024
2 parents e01b1f3 + f0571a3 commit 6be2e24
Showing 1 changed file with 25 additions and 0 deletions.
25 changes: 25 additions & 0 deletions LiteDB/Engine/Services/SnapShot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ internal class Snapshot : IDisposable
// local page cache - contains only pages about this collection (but do not contains CollectionPage - use this.CollectionPage)
private readonly Dictionary<uint, BasePage> _localPages = new Dictionary<uint, BasePage>();

private bool _disposed;

// expose
public LockMode Mode => _mode;
public string CollectionName => _collectionName;
Expand Down Expand Up @@ -89,6 +91,8 @@ public Snapshot(
/// </summary>
public IEnumerable<BasePage> GetWritablePages(bool dirty, bool includeCollectionPage)
{
ENSURE(!_disposed, "the snapshot is disposed");

// if snapshot is read only, just exit
if (_mode == LockMode.Read) yield break;

Expand All @@ -110,6 +114,8 @@ public IEnumerable<BasePage> GetWritablePages(bool dirty, bool includeCollection
/// </summary>
public void Clear()
{
ENSURE(!_disposed, "the snapshot is disposed");

// release pages only if snapshot are read only
if (_mode == LockMode.Read)
{
Expand All @@ -128,9 +134,16 @@ public void Clear()
/// </summary>
public void Dispose()
{
if (_disposed)
{
return;
}

// release all data/index pages
this.Clear();

_disposed = true;

// release collection page (in read mode)
if (_mode == LockMode.Read && _collectionPage != null)
{
Expand Down Expand Up @@ -160,6 +173,7 @@ public T GetPage<T>(uint pageID)
public T GetPage<T>(uint pageID, out FileOrigin origin, out long position, out int walVersion)
where T : BasePage
{
ENSURE(!_disposed, "the snapshot is disposed");
ENSURE(pageID <= _header.LastPageID, "request page must be less or equals lastest page in data file");

// check for header page (return header single instance)
Expand Down Expand Up @@ -259,6 +273,8 @@ private T ReadPage<T>(uint pageID, out FileOrigin origin, out long position, out
/// </summary>
public DataPage GetFreeDataPage(int bytesLength)
{
ENSURE(!_disposed, "the snapshot is disposed");

var length = bytesLength + BasePage.SLOT_SIZE; // add +4 bytes for footer slot

// get minimum slot to check for free page. Returns -1 if need NewPage
Expand Down Expand Up @@ -292,6 +308,8 @@ public DataPage GetFreeDataPage(int bytesLength)
/// </summary>
public IndexPage GetFreeIndexPage(int bytesLength, ref uint freeIndexPageList)
{
ENSURE(!_disposed, "the snapshot is disposed");

IndexPage page;

// if there is not page in list pages, create new page
Expand All @@ -318,6 +336,7 @@ public IndexPage GetFreeIndexPage(int bytesLength, ref uint freeIndexPageList)
public T NewPage<T>()
where T : BasePage
{
ENSURE(!_disposed, "the snapshot is disposed");
ENSURE(_collectionPage == null, typeof(T) == typeof(CollectionPage), "if no collection page defined yet, must be first request");
ENSURE(typeof(T) == typeof(CollectionPage), _collectionPage == null, "there is no new collection page if page already exists");

Expand Down Expand Up @@ -392,6 +411,8 @@ public T NewPage<T>()
/// </summary>
public void AddOrRemoveFreeDataList(DataPage page)
{
ENSURE(!_disposed, "the snapshot is disposed");

var newSlot = DataPage.FreeIndexSlot(page.FreeBytes);
var initialSlot = page.PageListSlot;

Expand Down Expand Up @@ -423,6 +444,8 @@ public void AddOrRemoveFreeDataList(DataPage page)
/// </summary>
public void AddOrRemoveFreeIndexList(IndexPage page, ref uint startPageID)
{
ENSURE(!_disposed, "the snapshot is disposed");

var newSlot = IndexPage.FreeIndexSlot(page.FreeBytes);
var isOnList = page.PageListSlot == 0;
var mustKeep = newSlot == 0;
Expand Down Expand Up @@ -567,6 +590,8 @@ private void DeletePage<T>(T page)
/// </summary>
public void DropCollection(Action safePoint)
{
ENSURE(!_disposed, "the snapshot is disposed");

var indexer = new IndexService(this, _header.Pragmas.Collation, _disk.MAX_ITEMS_COUNT);

// CollectionPage will be last deleted page (there is no NextPageID from CollectionPage)
Expand Down

0 comments on commit 6be2e24

Please sign in to comment.