Ctrl K
ComunidadGuías…

Ferrite.Data/UpdateState/FasterSettledPts.cs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2022-2026 Aykut Alparslan KOC

using FASTER.core;
using Ferrite.Data.Primitives;
using Ferrite.TL;
using Ferrite.TL.baseLayer.dto;

namespace Ferrite.Data.UpdateState;

internal sealed class FasterSettledPts(FasterContext<string, byte[]> context, long userId)
{
    public async ValueTask Settle(int first, int last)
    {
        ArgumentOutOfRangeException.ThrowIfLessThan(first, 1);
        ArgumentOutOfRangeException.ThrowIfLessThan(last, first);
        await Update(new Mutation(first, last, 1));
    }

    public ValueTask<int> Extend(int committed) => Update(new Mutation(0, 0, committed));

    private async ValueTask<int> Update(Mutation mutation)
    {
        using var session = context.Store.NewSession(new Functions());
        var result = await session.RMWAsync($"updates:settled-pts:{userId}", mutation);
        while (result.Status.IsPending)
        {
            result = await result.CompleteAsync();
        }
        if (result.Status.IsFaulted)
        {
            throw new InvalidOperationException("Could not update settled pts");
        }
        return result.Output;
    }

    private readonly record struct Mutation(int First, int Last, int Committed);

    private sealed class Functions : FunctionsBase<string, byte[], Mutation, int, Empty>
    {
        private static byte[] Apply(byte[]? bytes, Mutation input, out int committed)
        {
            committed = Math.Max(1, input.Committed);
            var ranges = new List<(int First, int Last)>();
            if (bytes != null)
            {
                var state = new SettledPts(bytes);
                committed = Math.Max(committed, state.Committed);
                var stored = state.Ranges;
                for (int i = 0; i < stored.Count; i++)
                {
                    var range = new PtsRange(stored.ReadTLObject());
                    ranges.Add((range.First, range.Last));
                }
            }
            if (input.First > 0)
            {
                ranges.Add((input.First, input.Last));
            }
            ranges.Sort();
            var pending = new List<(int First, int Last)>();
            foreach (var range in ranges)
            {
                if (range.First <= (long)committed + 1)
                {
                    committed = Math.Max(committed, range.Last);
                }
                else if (pending.Count > 0 && range.First <= (long)pending[^1].Last + 1)
                {
                    pending[^1] = (pending[^1].First, Math.Max(pending[^1].Last, range.Last));
                }
                else
                {
                    pending.Add(range);
                }
            }
            var vector = new Vector();
            foreach (var range in pending)
            {
                using TLPtsRange row = PtsRange.Builder().First(range.First).Last(range.Last).Build();
                vector.AppendTLObject(row.AsSpan());
            }
            using TLSettledPts updated = SettledPts.Builder().Committed(committed).Ranges(vector).Build();
            return updated.AsSpan().ToArray();
        }

        public override bool InitialUpdater(ref string key, ref Mutation input,
            ref byte[] value, ref int output, ref RMWInfo rmwInfo)
        {
            value = Apply(null, input, out output);
            return true;
        }

        public override bool CopyUpdater(ref string key, ref Mutation input,
            ref byte[] oldValue, ref byte[] newValue, ref int output, ref RMWInfo rmwInfo)
        {
            newValue = Apply(oldValue, input, out output);
            return true;
        }

        public override bool InPlaceUpdater(ref string key, ref Mutation input,
            ref byte[] value, ref int output, ref RMWInfo rmwInfo)
        {
            value = Apply(value, input, out output);
            return true;
        }
    }
}