simplify reconciliation

This commit is contained in:
Christien Rioux 2025-04-19 22:21:40 -04:00
parent bf38c2c44d
commit 4797184a1a
12 changed files with 512 additions and 345 deletions

View file

@ -9,64 +9,68 @@ import '../../../proto/proto.dart' as proto;
@immutable
class InputWindow {
const InputWindow(
{required this.elements, required this.first, required this.last});
const InputWindow({required this.elements, required this.firstPosition})
: lastPosition = firstPosition + elements.length - 1,
isEmpty = elements.length == 0,
length = elements.length;
final IList<OnlineElementState<proto.Message>> elements;
final int first;
final int last;
final int firstPosition;
final int lastPosition;
final bool isEmpty;
final int length;
}
class AuthorInputSource {
AuthorInputSource.fromCubit(
{required DHTLogStateData<proto.Message> cubitState,
required this.cubit}) {
_currentWindow = InputWindow(
elements: cubitState.window,
first: (cubitState.windowTail - cubitState.window.length) %
cubitState.length,
last: (cubitState.windowTail - 1) % cubitState.length);
}
AuthorInputSource.fromDHTLog(DHTLog dhtLog) : _dhtLog = dhtLog;
////////////////////////////////////////////////////////////////////////////
InputWindow get currentWindow => _currentWindow;
Future<int> getTailPosition() async =>
_dhtLog.operate((reader) async => reader.length);
Future<AsyncValue<bool>> updateWindow(
int currentPosition, int windowLength) async =>
cubit.operate((reader) async {
// See if we're beyond the input source
if (currentPosition < 0 || currentPosition >= reader.length) {
return const AsyncValue.data(false);
}
// Slide the window if we need to
var first = _currentWindow.first;
var last = _currentWindow.last;
if (currentPosition < first) {
// Slide it backward, current position is now last
first = max((currentPosition - windowLength) + 1, 0);
last = currentPosition;
} else if (currentPosition > last) {
// Slide it forward, current position is now first
first = currentPosition;
last = min((currentPosition + windowLength) - 1, reader.length - 1);
} else {
return const AsyncValue.data(true);
Future<AsyncValue<InputWindow?>> getWindow(
int startPosition, int windowLength) async =>
_dhtLog.operate((reader) async {
// Don't allow negative length
if (windowLength <= 0) {
return const AsyncValue.data(null);
}
// Trim if we're beyond input source
var endPosition = startPosition + windowLength - 1;
startPosition = max(startPosition, 0);
endPosition = max(endPosition, 0);
// Get another input batch futher back
final nextWindow = await cubit.loadElementsFromReader(
reader, last + 1, (last + 1) - first);
if (nextWindow == null) {
return const AsyncValue.loading();
try {
Set<int>? offlinePositions;
if (_dhtLog.writer != null) {
offlinePositions = await reader.getOfflinePositions();
}
final messages = await reader.getRangeProtobuf(
proto.Message.fromBuffer, startPosition,
length: endPosition - startPosition + 1);
if (messages == null) {
return const AsyncValue.loading();
}
final elements = messages.indexed
.map((x) => OnlineElementState(
value: x.$2,
isOffline: offlinePositions?.contains(x.$1 + startPosition) ??
false))
.toIList();
final window =
InputWindow(elements: elements, firstPosition: startPosition);
return AsyncValue.data(window);
} on Exception catch (e, st) {
return AsyncValue.error(e, st);
}
_currentWindow =
InputWindow(elements: nextWindow, first: first, last: last);
return const AsyncValue.data(true);
});
////////////////////////////////////////////////////////////////////////////
final DHTLogCubit<proto.Message> cubit;
late InputWindow _currentWindow;
final DHTLog _dhtLog;
}