Add Gitea NuGet publish workflow and finalize current storage/index/docs updates.
This commit is contained in:
76
.gitea/workflows/nuget-publish.yml
Normal file
76
.gitea/workflows/nuget-publish.yml
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
name: NuGet Publish
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "**"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-pack:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: mcr.microsoft.com/dotnet/sdk:10.0
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Restore
|
||||||
|
run: dotnet restore CBDD.slnx
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: dotnet build CBDD.slnx -c Release --no-restore
|
||||||
|
|
||||||
|
- name: Pack NuGet Packages
|
||||||
|
run: |
|
||||||
|
mkdir -p nupkgs
|
||||||
|
dotnet pack src/CBDD/ZB.MOM.WW.CBDD.csproj -c Release -o nupkgs --no-build
|
||||||
|
dotnet pack src/CBDD.Bson/ZB.MOM.WW.CBDD.Bson.csproj -c Release -o nupkgs --no-build
|
||||||
|
dotnet pack src/CBDD.Core/ZB.MOM.WW.CBDD.Core.csproj -c Release -o nupkgs --no-build
|
||||||
|
dotnet pack src/CBDD.SourceGenerators/ZB.MOM.WW.CBDD.SourceGenerators.csproj -c Release -o nupkgs --no-build
|
||||||
|
|
||||||
|
- name: Upload Package Artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: nuget-packages
|
||||||
|
path: nupkgs/*.nupkg
|
||||||
|
|
||||||
|
publish-to-gitea:
|
||||||
|
needs: build-and-pack
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ gitea.ref == 'refs/heads/main' && secrets.GITEA_NUGET_USERNAME != '' && secrets.GITEA_NUGET_TOKEN != '' }}
|
||||||
|
container:
|
||||||
|
image: mcr.microsoft.com/dotnet/sdk:10.0
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Restore
|
||||||
|
run: dotnet restore CBDD.slnx
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: dotnet build CBDD.slnx -c Release --no-restore
|
||||||
|
|
||||||
|
- name: Pack NuGet Packages
|
||||||
|
run: |
|
||||||
|
mkdir -p nupkgs
|
||||||
|
dotnet pack src/CBDD/ZB.MOM.WW.CBDD.csproj -c Release -o nupkgs --no-build
|
||||||
|
dotnet pack src/CBDD.Bson/ZB.MOM.WW.CBDD.Bson.csproj -c Release -o nupkgs --no-build
|
||||||
|
dotnet pack src/CBDD.Core/ZB.MOM.WW.CBDD.Core.csproj -c Release -o nupkgs --no-build
|
||||||
|
dotnet pack src/CBDD.SourceGenerators/ZB.MOM.WW.CBDD.SourceGenerators.csproj -c Release -o nupkgs --no-build
|
||||||
|
|
||||||
|
- name: Configure Gitea NuGet Source
|
||||||
|
run: |
|
||||||
|
dotnet nuget add source \
|
||||||
|
"https://gitea.dohertylan.com/api/packages/dohertj2/nuget/index.json" \
|
||||||
|
--name gitea \
|
||||||
|
--username "${{ secrets.GITEA_NUGET_USERNAME }}" \
|
||||||
|
--password "${{ secrets.GITEA_NUGET_TOKEN }}" \
|
||||||
|
--store-password-in-clear-text
|
||||||
|
|
||||||
|
- name: Publish Packages
|
||||||
|
run: |
|
||||||
|
for pkg in nupkgs/*.nupkg; do
|
||||||
|
if [ -f "$pkg" ] && [[ "$pkg" != *.snupkg ]]; then
|
||||||
|
dotnet nuget push "$pkg" --source gitea --skip-duplicate
|
||||||
|
fi
|
||||||
|
done
|
||||||
40
README.md
40
README.md
@@ -10,21 +10,21 @@ CBDD provides a local data layer for services and tools that need transactional
|
|||||||
|
|
||||||
- Owning team: CBDD maintainers (repository owner: `@dohertj2`)
|
- Owning team: CBDD maintainers (repository owner: `@dohertj2`)
|
||||||
- Primary support path: open a Gitea issue in this repository with labels `incident` or `bug`
|
- Primary support path: open a Gitea issue in this repository with labels `incident` or `bug`
|
||||||
- Escalation path: follow `/Users/dohertj2/Desktop/CBDD/docs/runbook.md` and page the release maintainer listed in the active release PR
|
- Escalation path: follow [`docs/runbook.md`](docs/runbook.md) and page the release maintainer listed in the active release PR
|
||||||
|
|
||||||
## Architecture Overview
|
## Architecture Overview
|
||||||
|
|
||||||
CBDD has four primary layers:
|
CBDD has four primary layers:
|
||||||
|
|
||||||
1. Storage and transaction engine (`/Users/dohertj2/Desktop/CBDD/src/CBDD.Core/Storage`, `/Users/dohertj2/Desktop/CBDD/src/CBDD.Core/Transactions`)
|
1. Storage and transaction engine (`src/CBDD.Core/Storage`, `src/CBDD.Core/Transactions`)
|
||||||
2. BSON serialization (`/Users/dohertj2/Desktop/CBDD/src/CBDD.Bson`)
|
2. BSON serialization (`src/CBDD.Bson`)
|
||||||
3. Indexing and query execution (`/Users/dohertj2/Desktop/CBDD/src/CBDD.Core/Indexing`, `/Users/dohertj2/Desktop/CBDD/src/CBDD.Core/Query`)
|
3. Indexing and query execution (`src/CBDD.Core/Indexing`, `src/CBDD.Core/Query`)
|
||||||
4. Source-generated mapping (`/Users/dohertj2/Desktop/CBDD/src/CBDD.SourceGenerators`)
|
4. Source-generated mapping (`src/CBDD.SourceGenerators`)
|
||||||
|
|
||||||
Detailed architecture material:
|
Detailed architecture material:
|
||||||
- `/Users/dohertj2/Desktop/CBDD/docs/architecture.md`
|
- [`docs/architecture.md`](docs/architecture.md)
|
||||||
- `/Users/dohertj2/Desktop/CBDD/RFC.md`
|
- [`RFC.md`](RFC.md)
|
||||||
- `/Users/dohertj2/Desktop/CBDD/C-BSON.md`
|
- [`C-BSON.md`](C-BSON.md)
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@@ -94,29 +94,29 @@ bash scripts/fitness-check.sh
|
|||||||
|
|
||||||
CBDD is released as an internal package.
|
CBDD is released as an internal package.
|
||||||
|
|
||||||
- Deployment workflow: `/Users/dohertj2/Desktop/CBDD/docs/deployment.md`
|
- Deployment workflow: [`docs/deployment.md`](docs/deployment.md)
|
||||||
- Rollback workflow: `/Users/dohertj2/Desktop/CBDD/docs/deployment.md#rollback-procedure`
|
- Rollback workflow: [`docs/deployment.md#rollback-procedure`](docs/deployment.md#rollback-procedure)
|
||||||
|
|
||||||
## Operations And Incident Response
|
## Operations And Incident Response
|
||||||
|
|
||||||
Operational procedures, diagnostics, and escalation are documented in:
|
Operational procedures, diagnostics, and escalation are documented in:
|
||||||
|
|
||||||
- `/Users/dohertj2/Desktop/CBDD/docs/runbook.md`
|
- [`docs/runbook.md`](docs/runbook.md)
|
||||||
- `/Users/dohertj2/Desktop/CBDD/docs/troubleshooting.md`
|
- [`docs/troubleshooting.md`](docs/troubleshooting.md)
|
||||||
|
|
||||||
## Security And Compliance Posture
|
## Security And Compliance Posture
|
||||||
|
|
||||||
- CBDD relies on host and process-level access controls.
|
- CBDD relies on host and process-level access controls.
|
||||||
- Sensitive payload classification and handling requirements are defined in `/Users/dohertj2/Desktop/CBDD/docs/security.md`.
|
- Sensitive payload classification and handling requirements are defined in [`docs/security.md`](docs/security.md).
|
||||||
- Role and approval requirements are defined in `/Users/dohertj2/Desktop/CBDD/docs/access.md`.
|
- Role and approval requirements are defined in [`docs/access.md`](docs/access.md).
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
Common issues and remediation:
|
Common issues and remediation:
|
||||||
|
|
||||||
- Build/test environment failures: `/Users/dohertj2/Desktop/CBDD/docs/troubleshooting.md#build-and-test-failures`
|
- Build/test environment failures: [`docs/troubleshooting.md#build-and-test-failures`](docs/troubleshooting.md#build-and-test-failures)
|
||||||
- Data-file recovery procedures: `/Users/dohertj2/Desktop/CBDD/docs/troubleshooting.md#data-file-and-recovery-issues`
|
- Data-file recovery procedures: [`docs/troubleshooting.md#data-file-and-recovery-issues`](docs/troubleshooting.md#data-file-and-recovery-issues)
|
||||||
- Query/index behavior verification: `/Users/dohertj2/Desktop/CBDD/docs/troubleshooting.md#query-and-index-issues`
|
- Query/index behavior verification: [`docs/troubleshooting.md#query-and-index-issues`](docs/troubleshooting.md#query-and-index-issues)
|
||||||
|
|
||||||
## Change Governance
|
## Change Governance
|
||||||
|
|
||||||
@@ -127,6 +127,6 @@ Common issues and remediation:
|
|||||||
|
|
||||||
## Documentation Index
|
## Documentation Index
|
||||||
|
|
||||||
- Documentation home: `/Users/dohertj2/Desktop/CBDD/docs/README.md`
|
- Documentation home: [`docs/README.md`](docs/README.md)
|
||||||
- Major feature inventory: `/Users/dohertj2/Desktop/CBDD/docs/features/README.md`
|
- Major feature inventory: [`docs/features/README.md`](docs/features/README.md)
|
||||||
- Architecture decisions: `/Users/dohertj2/Desktop/CBDD/docs/adr/0001-storage-engine-and-source-generation.md`
|
- Architecture decisions: [`docs/adr/0001-storage-engine-and-source-generation.md`](docs/adr/0001-storage-engine-and-source-generation.md)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using ZB.MOM.WW.CBDD.Core;
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("ZB.MOM.WW.CBDD.Tests")]
|
[assembly: InternalsVisibleTo("ZB.MOM.WW.CBDD.Tests")]
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ public class DocumentCollection<T> : DocumentCollection<ObjectId, T> where T : c
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TId">Type of the primary key</typeparam>
|
/// <typeparam name="TId">Type of the primary key</typeparam>
|
||||||
/// <typeparam name="T">Type of the entity</typeparam>
|
/// <typeparam name="T">Type of the entity</typeparam>
|
||||||
public partial class DocumentCollection<TId, T> : IDisposable where T : class
|
public partial class DocumentCollection<TId, T> : IDisposable, ICompactionAwareCollection where T : class
|
||||||
{
|
{
|
||||||
private readonly ITransactionHolder _transactionHolder;
|
private readonly ITransactionHolder _transactionHolder;
|
||||||
private readonly IStorageEngine _storage;
|
private readonly IStorageEngine _storage;
|
||||||
@@ -130,15 +131,27 @@ public partial class DocumentCollection<TId, T> : IDisposable where T : class
|
|||||||
|
|
||||||
private void RefreshPrimaryIndexRootFromMetadata()
|
private void RefreshPrimaryIndexRootFromMetadata()
|
||||||
{
|
{
|
||||||
_indexManager.RefreshFromStorageMetadata();
|
var metadata = _storage.GetCollectionMetadata(_collectionName);
|
||||||
|
if (metadata == null || metadata.PrimaryRootPageId == 0)
|
||||||
var primaryRootPageId = _indexManager.PrimaryRootPageId;
|
|
||||||
if (primaryRootPageId == 0)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (primaryRootPageId != _primaryIndex.RootPageId)
|
if (metadata.PrimaryRootPageId != _primaryIndex.RootPageId)
|
||||||
{
|
{
|
||||||
_primaryIndex.SetRootPageId(primaryRootPageId);
|
_primaryIndex.SetRootPageId(metadata.PrimaryRootPageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICompactionAwareCollection.RefreshIndexBindingsAfterCompaction()
|
||||||
|
{
|
||||||
|
var metadata = _storage.GetCollectionMetadata(_collectionName);
|
||||||
|
if (metadata == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_indexManager.RebindFromMetadata(metadata);
|
||||||
|
|
||||||
|
if (metadata.PrimaryRootPageId != 0 && metadata.PrimaryRootPageId != _primaryIndex.RootPageId)
|
||||||
|
{
|
||||||
|
_primaryIndex.SetRootPageId(metadata.PrimaryRootPageId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ using ZB.MOM.WW.CBDD.Bson;
|
|||||||
|
|
||||||
namespace ZB.MOM.WW.CBDD.Core;
|
namespace ZB.MOM.WW.CBDD.Core;
|
||||||
|
|
||||||
|
internal interface ICompactionAwareCollection
|
||||||
|
{
|
||||||
|
void RefreshIndexBindingsAfterCompaction();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base class for database contexts.
|
/// Base class for database contexts.
|
||||||
/// Inherit and add DocumentCollection{T} properties for your entities.
|
/// Inherit and add DocumentCollection{T} properties for your entities.
|
||||||
@@ -103,6 +108,7 @@ public abstract partial class DocumentDbContext : IDisposable, ITransactionHolde
|
|||||||
|
|
||||||
private readonly IReadOnlyDictionary<Type, object> _model;
|
private readonly IReadOnlyDictionary<Type, object> _model;
|
||||||
private readonly List<IDocumentMapper> _registeredMappers = new();
|
private readonly List<IDocumentMapper> _registeredMappers = new();
|
||||||
|
private readonly List<ICompactionAwareCollection> _compactionAwareCollections = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the concrete storage engine for advanced scenarios in derived contexts.
|
/// Gets the concrete storage engine for advanced scenarios in derived contexts.
|
||||||
@@ -157,6 +163,10 @@ public abstract partial class DocumentDbContext : IDisposable, ITransactionHolde
|
|||||||
|
|
||||||
_registeredMappers.Add(mapper);
|
_registeredMappers.Add(mapper);
|
||||||
var collection = new DocumentCollection<TId, T>(_storage, this, mapper, customName);
|
var collection = new DocumentCollection<TId, T>(_storage, this, mapper, customName);
|
||||||
|
if (collection is ICompactionAwareCollection compactionAwareCollection)
|
||||||
|
{
|
||||||
|
_compactionAwareCollections.Add(compactionAwareCollection);
|
||||||
|
}
|
||||||
|
|
||||||
// Apply configurations from ModelBuilder
|
// Apply configurations from ModelBuilder
|
||||||
if (builder != null)
|
if (builder != null)
|
||||||
@@ -335,7 +345,9 @@ public abstract partial class DocumentDbContext : IDisposable, ITransactionHolde
|
|||||||
if (_disposed)
|
if (_disposed)
|
||||||
throw new ObjectDisposedException(nameof(DocumentDbContext));
|
throw new ObjectDisposedException(nameof(DocumentDbContext));
|
||||||
|
|
||||||
return Engine.Compact(options);
|
var stats = Engine.Compact(options);
|
||||||
|
RefreshCollectionBindingsAfterCompaction();
|
||||||
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -346,7 +358,7 @@ public abstract partial class DocumentDbContext : IDisposable, ITransactionHolde
|
|||||||
if (_disposed)
|
if (_disposed)
|
||||||
throw new ObjectDisposedException(nameof(DocumentDbContext));
|
throw new ObjectDisposedException(nameof(DocumentDbContext));
|
||||||
|
|
||||||
return Engine.CompactAsync(options, ct);
|
return CompactAsyncCore(options, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -357,7 +369,9 @@ public abstract partial class DocumentDbContext : IDisposable, ITransactionHolde
|
|||||||
if (_disposed)
|
if (_disposed)
|
||||||
throw new ObjectDisposedException(nameof(DocumentDbContext));
|
throw new ObjectDisposedException(nameof(DocumentDbContext));
|
||||||
|
|
||||||
return Engine.Vacuum(options);
|
var stats = Engine.Vacuum(options);
|
||||||
|
RefreshCollectionBindingsAfterCompaction();
|
||||||
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -368,7 +382,29 @@ public abstract partial class DocumentDbContext : IDisposable, ITransactionHolde
|
|||||||
if (_disposed)
|
if (_disposed)
|
||||||
throw new ObjectDisposedException(nameof(DocumentDbContext));
|
throw new ObjectDisposedException(nameof(DocumentDbContext));
|
||||||
|
|
||||||
return Engine.VacuumAsync(options, ct);
|
return VacuumAsyncCore(options, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<CompactionStats> CompactAsyncCore(CompactionOptions? options, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var stats = await Engine.CompactAsync(options, ct);
|
||||||
|
RefreshCollectionBindingsAfterCompaction();
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<CompactionStats> VacuumAsyncCore(CompactionOptions? options, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var stats = await Engine.VacuumAsync(options, ct);
|
||||||
|
RefreshCollectionBindingsAfterCompaction();
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshCollectionBindingsAfterCompaction()
|
||||||
|
{
|
||||||
|
foreach (var collection in _compactionAwareCollections)
|
||||||
|
{
|
||||||
|
collection.RefreshIndexBindingsAfterCompaction();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -505,26 +505,25 @@ public sealed class CollectionIndexManager<TId, T> : IDisposable where T : class
|
|||||||
public uint PrimaryRootPageId => _metadata.PrimaryRootPageId;
|
public uint PrimaryRootPageId => _metadata.PrimaryRootPageId;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Refreshes cached metadata and index root bindings from storage.
|
/// Rebinds cached metadata and index instances from persisted metadata.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal void RefreshFromStorageMetadata()
|
internal void RebindFromMetadata(CollectionMetadata metadata)
|
||||||
{
|
{
|
||||||
|
if (metadata == null)
|
||||||
|
throw new ArgumentNullException(nameof(metadata));
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
throw new ObjectDisposedException(nameof(CollectionIndexManager<TId, T>));
|
throw new ObjectDisposedException(nameof(CollectionIndexManager<TId, T>));
|
||||||
|
|
||||||
var latest = _storage.GetCollectionMetadata(_collectionName) ?? new CollectionMetadata { Name = _collectionName };
|
|
||||||
if (MetadataEquals(_metadata, latest))
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var index in _indexes.Values)
|
foreach (var index in _indexes.Values)
|
||||||
{
|
{
|
||||||
try { index.Dispose(); } catch { /* Best effort */ }
|
try { index.Dispose(); } catch { /* Best effort */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
_indexes.Clear();
|
_indexes.Clear();
|
||||||
_metadata = latest;
|
_metadata = metadata;
|
||||||
|
|
||||||
foreach (var idxMeta in _metadata.Indexes)
|
foreach (var idxMeta in _metadata.Indexes)
|
||||||
{
|
{
|
||||||
@@ -563,47 +562,6 @@ public sealed class CollectionIndexManager<TId, T> : IDisposable where T : class
|
|||||||
_storage.SaveCollectionMetadata(_metadata);
|
_storage.SaveCollectionMetadata(_metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool MetadataEquals(CollectionMetadata left, CollectionMetadata right)
|
|
||||||
{
|
|
||||||
if (!string.Equals(left.Name, right.Name, StringComparison.OrdinalIgnoreCase))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (left.PrimaryRootPageId != right.PrimaryRootPageId ||
|
|
||||||
left.SchemaRootPageId != right.SchemaRootPageId ||
|
|
||||||
left.Indexes.Count != right.Indexes.Count)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < left.Indexes.Count; i++)
|
|
||||||
{
|
|
||||||
var l = left.Indexes[i];
|
|
||||||
var r = right.Indexes[i];
|
|
||||||
if (!string.Equals(l.Name, r.Name, StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
l.RootPageId != r.RootPageId ||
|
|
||||||
l.Type != r.Type ||
|
|
||||||
l.IsUnique != r.IsUnique ||
|
|
||||||
l.Dimensions != r.Dimensions ||
|
|
||||||
l.Metric != r.Metric)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var lPaths = l.PropertyPaths ?? Array.Empty<string>();
|
|
||||||
var rPaths = r.PropertyPaths ?? Array.Empty<string>();
|
|
||||||
if (lPaths.Length != rPaths.Length)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (var p = 0; p < lPaths.Length; p++)
|
|
||||||
{
|
|
||||||
if (!string.Equals(lPaths[p], rPaths[p], StringComparison.Ordinal))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Releases resources used by the index manager.
|
/// Releases resources used by the index manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -779,17 +779,28 @@ public sealed partial class StorageEngine
|
|||||||
private CompactionSnapshot CaptureCompactionSnapshot()
|
private CompactionSnapshot CaptureCompactionSnapshot()
|
||||||
{
|
{
|
||||||
var fileSizeBytes = _pageFile.FileLengthBytes;
|
var fileSizeBytes = _pageFile.FileLengthBytes;
|
||||||
var pageCount = _pageFile.NextPageId;
|
var logicalPageCount = _pageFile.NextPageId;
|
||||||
var pageSize = _pageFile.PageSize;
|
var pageSize = _pageFile.PageSize;
|
||||||
|
var pageCount = (uint)(fileSizeBytes / pageSize);
|
||||||
|
|
||||||
var freePages = _pageFile.EnumerateFreePages(includeEmptyPages: true);
|
var freePages = _pageFile.EnumerateFreePages(includeEmptyPages: true);
|
||||||
var freePageCount = freePages.Count;
|
var freePageSet = new HashSet<uint>(freePages);
|
||||||
|
|
||||||
|
if (pageCount > logicalPageCount)
|
||||||
|
{
|
||||||
|
for (var pageId = logicalPageCount; pageId < pageCount; pageId++)
|
||||||
|
{
|
||||||
|
freePageSet.Add(pageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var freePageCount = freePageSet.Count;
|
||||||
|
|
||||||
long slottedFreeBytes = 0;
|
long slottedFreeBytes = 0;
|
||||||
if (pageCount > 1)
|
if (logicalPageCount > 1)
|
||||||
{
|
{
|
||||||
var pageBuffer = new byte[pageSize];
|
var pageBuffer = new byte[pageSize];
|
||||||
for (uint pageId = 1; pageId < pageCount; pageId++)
|
for (uint pageId = 1; pageId < logicalPageCount; pageId++)
|
||||||
{
|
{
|
||||||
_pageFile.ReadPage(pageId, pageBuffer);
|
_pageFile.ReadPage(pageId, pageBuffer);
|
||||||
if (!TryReadSlottedFreeSpace(pageBuffer, out var availableFreeSpace))
|
if (!TryReadSlottedFreeSpace(pageBuffer, out var availableFreeSpace))
|
||||||
@@ -805,7 +816,6 @@ public sealed partial class StorageEngine
|
|||||||
? 0
|
? 0
|
||||||
: (totalFreeBytes * 100d) / fileSizeBytes;
|
: (totalFreeBytes * 100d) / fileSizeBytes;
|
||||||
|
|
||||||
var freePageSet = new HashSet<uint>(freePages);
|
|
||||||
uint tailReclaimablePages = 0;
|
uint tailReclaimablePages = 0;
|
||||||
for (var pageId = pageCount; pageId > 2; pageId--)
|
for (var pageId = pageCount; pageId > 2; pageId--)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user