mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2024-10-01 06:55:46 -04:00
tests pass
This commit is contained in:
parent
ed893852a2
commit
ff1ea709a8
@ -1,10 +1,6 @@
|
|||||||
//@Timeout(Duration(seconds: 240))
|
|
||||||
|
|
||||||
//library veilid_support_integration_test;
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:test/test.dart';
|
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
import 'package:veilid_test/veilid_test.dart';
|
import 'package:veilid_test/veilid_test.dart';
|
||||||
|
|
||||||
import 'fixtures/fixtures.dart';
|
import 'fixtures/fixtures.dart';
|
||||||
@ -26,7 +22,7 @@ void main() {
|
|||||||
tickerFixture: tickerFixture,
|
tickerFixture: tickerFixture,
|
||||||
updateProcessorFixture: updateProcessorFixture);
|
updateProcessorFixture: updateProcessorFixture);
|
||||||
|
|
||||||
group('Started Tests', () {
|
group(timeout: const Timeout(Duration(seconds: 240)), 'Started Tests', () {
|
||||||
setUpAll(veilidFixture.setUp);
|
setUpAll(veilidFixture.setUp);
|
||||||
tearDownAll(veilidFixture.tearDown);
|
tearDownAll(veilidFixture.tearDown);
|
||||||
tearDownAll(() {
|
tearDownAll(() {
|
||||||
@ -74,9 +70,11 @@ void main() {
|
|||||||
for (final stride in [256, 16 /*64, 32, 16, 8, 4, 2, 1 */]) {
|
for (final stride in [256, 16 /*64, 32, 16, 8, 4, 2, 1 */]) {
|
||||||
test('create log stride=$stride',
|
test('create log stride=$stride',
|
||||||
makeTestDHTLogCreateDelete(stride: stride));
|
makeTestDHTLogCreateDelete(stride: stride));
|
||||||
test('add/truncate log stride=$stride',
|
test(
|
||||||
|
timeout: const Timeout(Duration(seconds: 480)),
|
||||||
|
'add/truncate log stride=$stride',
|
||||||
makeTestDHTLogAddTruncate(stride: stride),
|
makeTestDHTLogAddTruncate(stride: stride),
|
||||||
timeout: const Timeout(Duration(seconds: 480)));
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'package:veilid_support/veilid_support.dart';
|
import 'package:veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
Future<void> Function() makeTestDHTLogCreateDelete({required int stride}) =>
|
Future<void> Function() makeTestDHTLogCreateDelete({required int stride}) =>
|
||||||
@ -61,7 +61,7 @@ Future<void> Function() makeTestDHTLogAddTruncate({required int stride}) =>
|
|||||||
print('adding\n');
|
print('adding\n');
|
||||||
{
|
{
|
||||||
final res = await dlog.operateAppend((w) async {
|
final res = await dlog.operateAppend((w) async {
|
||||||
const chunk = 50;
|
const chunk = 25;
|
||||||
for (var n = 0; n < dataset.length; n += chunk) {
|
for (var n = 0; n < dataset.length; n += chunk) {
|
||||||
print('$n-${n + chunk - 1} ');
|
print('$n-${n + chunk - 1} ');
|
||||||
final success =
|
final success =
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'package:veilid_support/veilid_support.dart';
|
import 'package:veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
Future<void> testDHTRecordPoolCreate() async {
|
Future<void> testDHTRecordPoolCreate() async {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'package:veilid_support/veilid_support.dart';
|
import 'package:veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
Future<void> Function() makeTestDHTShortArrayCreateDelete(
|
Future<void> Function() makeTestDHTShortArrayCreateDelete(
|
||||||
@ -118,7 +118,10 @@ Future<void> Function() makeTestDHTShortArrayAdd({required int stride}) =>
|
|||||||
|
|
||||||
//print('clear\n');
|
//print('clear\n');
|
||||||
{
|
{
|
||||||
await arr.operateWrite((w) async => w.clear());
|
await arr.operateWriteEventual((w) async {
|
||||||
|
await w.clear();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//print('get all\n');
|
//print('get all\n');
|
||||||
|
@ -196,7 +196,7 @@ packages:
|
|||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
@ -15,8 +15,6 @@ dependencies:
|
|||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
async_tools: ^0.1.1
|
async_tools: ^0.1.1
|
||||||
flutter_test:
|
|
||||||
sdk: flutter
|
|
||||||
integration_test:
|
integration_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
lint_hard: ^4.0.0
|
lint_hard: ^4.0.0
|
||||||
|
@ -42,7 +42,7 @@ class DHTLogUpdate extends Equatable {
|
|||||||
/// * The head and tail position of the log
|
/// * The head and tail position of the log
|
||||||
/// - subkeyIdx = pos / recordsPerSubkey
|
/// - subkeyIdx = pos / recordsPerSubkey
|
||||||
/// - recordIdx = pos % recordsPerSubkey
|
/// - recordIdx = pos % recordsPerSubkey
|
||||||
class DHTLog implements DHTOpenable<DHTLog> {
|
class DHTLog implements DHTDeleteable<DHTLog, DHTLog> {
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
@ -160,12 +160,16 @@ class DHTLog implements DHTOpenable<DHTLog> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// DHTOpenable
|
// DHTCloseable
|
||||||
|
|
||||||
/// Check if the DHTLog is open
|
/// Check if the DHTLog is open
|
||||||
@override
|
@override
|
||||||
bool get isOpen => _openCount > 0;
|
bool get isOpen => _openCount > 0;
|
||||||
|
|
||||||
|
/// The type of the openable scope
|
||||||
|
@override
|
||||||
|
FutureOr<DHTLog> scoped() => this;
|
||||||
|
|
||||||
/// Add a reference to this log
|
/// Add a reference to this log
|
||||||
@override
|
@override
|
||||||
Future<DHTLog> ref() async => _mutex.protect(() async {
|
Future<DHTLog> ref() async => _mutex.protect(() async {
|
||||||
|
@ -17,7 +17,7 @@ class _DHTLogAppend extends _DHTLogRead implements DHTAppendTruncateRandomRead {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write item to the segment
|
// Write item to the segment
|
||||||
return lookup.shortArray.scope((sa) => sa.operateWrite((write) async {
|
return lookup.scope((sa) => sa.operateWrite((write) async {
|
||||||
// If this a new segment, then clear it in case we have wrapped around
|
// If this a new segment, then clear it in case we have wrapped around
|
||||||
if (lookup.pos == 0) {
|
if (lookup.pos == 0) {
|
||||||
await write.clear();
|
await write.clear();
|
||||||
@ -51,8 +51,7 @@ class _DHTLogAppend extends _DHTLogRead implements DHTAppendTruncateRandomRead {
|
|||||||
final sublistValues = values.sublist(valueIdx, valueIdx + sacount);
|
final sublistValues = values.sublist(valueIdx, valueIdx + sacount);
|
||||||
|
|
||||||
dws.add(() async {
|
dws.add(() async {
|
||||||
final ok = await lookup.shortArray
|
final ok = await lookup.scope((sa) => sa.operateWrite((write) async {
|
||||||
.scope((sa) => sa.operateWrite((write) async {
|
|
||||||
// If this a new segment, then clear it in
|
// If this a new segment, then clear it in
|
||||||
// case we have wrapped around
|
// case we have wrapped around
|
||||||
if (lookup.pos == 0) {
|
if (lookup.pos == 0) {
|
||||||
@ -71,7 +70,7 @@ class _DHTLogAppend extends _DHTLogRead implements DHTAppendTruncateRandomRead {
|
|||||||
valueIdx += sacount;
|
valueIdx += sacount;
|
||||||
}
|
}
|
||||||
|
|
||||||
await dws(chunkSize: maxDHTConcurrency);
|
await dws();
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ class _DHTLogRead implements DHTRandomRead {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return lookup.shortArray.scope((sa) => sa.operate(
|
return lookup.scope((sa) => sa.operate(
|
||||||
(read) => read.getItem(lookup.pos, forceRefresh: forceRefresh)));
|
(read) => read.getItem(lookup.pos, forceRefresh: forceRefresh)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ class _DHTLogRead implements DHTRandomRead {
|
|||||||
|
|
||||||
// Check each segment for offline positions
|
// Check each segment for offline positions
|
||||||
var foundOffline = false;
|
var foundOffline = false;
|
||||||
await lookup.shortArray.scope((sa) => sa.operate((read) async {
|
await lookup.scope((sa) => sa.operate((read) async {
|
||||||
final segmentOffline = await read.getOfflinePositions();
|
final segmentOffline = await read.getOfflinePositions();
|
||||||
|
|
||||||
// For each shortarray segment go through their segment positions
|
// For each shortarray segment go through their segment positions
|
||||||
|
@ -1,9 +1,58 @@
|
|||||||
part of 'dht_log.dart';
|
part of 'dht_log.dart';
|
||||||
|
|
||||||
class DHTLogPositionLookup {
|
class _DHTLogPosition extends DHTCloseable<_DHTLogPosition, DHTShortArray> {
|
||||||
const DHTLogPositionLookup({required this.shortArray, required this.pos});
|
_DHTLogPosition._({
|
||||||
final DHTShortArray shortArray;
|
required _DHTLogSpine dhtLogSpine,
|
||||||
|
required DHTShortArray shortArray,
|
||||||
|
required this.pos,
|
||||||
|
required int segmentNumber,
|
||||||
|
}) : _segmentShortArray = shortArray,
|
||||||
|
_dhtLogSpine = dhtLogSpine,
|
||||||
|
_segmentNumber = segmentNumber;
|
||||||
final int pos;
|
final int pos;
|
||||||
|
|
||||||
|
final _DHTLogSpine _dhtLogSpine;
|
||||||
|
final DHTShortArray _segmentShortArray;
|
||||||
|
var _openCount = 1;
|
||||||
|
final int _segmentNumber;
|
||||||
|
final Mutex _mutex = Mutex();
|
||||||
|
|
||||||
|
/// Check if the DHTLogPosition is open
|
||||||
|
@override
|
||||||
|
bool get isOpen => _openCount > 0;
|
||||||
|
|
||||||
|
/// The type of the openable scope
|
||||||
|
@override
|
||||||
|
FutureOr<DHTShortArray> scoped() => _segmentShortArray;
|
||||||
|
|
||||||
|
/// Add a reference to this log
|
||||||
|
@override
|
||||||
|
Future<_DHTLogPosition> ref() async => _mutex.protect(() async {
|
||||||
|
_openCount++;
|
||||||
|
return this;
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Free all resources for the DHTLogPosition
|
||||||
|
@override
|
||||||
|
Future<void> close() async => _mutex.protect(() async {
|
||||||
|
if (_openCount == 0) {
|
||||||
|
throw StateError('already closed');
|
||||||
|
}
|
||||||
|
_openCount--;
|
||||||
|
if (_openCount != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await _dhtLogSpine._segmentClosed(_segmentNumber);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class _OpenedSegment {
|
||||||
|
_OpenedSegment._({
|
||||||
|
required this.shortArray,
|
||||||
|
});
|
||||||
|
|
||||||
|
final DHTShortArray shortArray;
|
||||||
|
int openCount = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DHTLogSegmentLookup extends Equatable {
|
class _DHTLogSegmentLookup extends Equatable {
|
||||||
@ -32,6 +81,7 @@ class _DHTLogSpine {
|
|||||||
_head = head,
|
_head = head,
|
||||||
_tail = tail,
|
_tail = tail,
|
||||||
_segmentStride = stride,
|
_segmentStride = stride,
|
||||||
|
_openedSegments = {},
|
||||||
_spineCache = [];
|
_spineCache = [];
|
||||||
|
|
||||||
// Create a new spine record and push it to the network
|
// Create a new spine record and push it to the network
|
||||||
@ -85,6 +135,8 @@ class _DHTLogSpine {
|
|||||||
futures.add(sc.close());
|
futures.add(sc.close());
|
||||||
}
|
}
|
||||||
await Future.wait(futures);
|
await Future.wait(futures);
|
||||||
|
|
||||||
|
assert(_openedSegments.isEmpty, 'should have closed all segments by now');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +299,7 @@ class _DHTLogSpine {
|
|||||||
|
|
||||||
// Lookup what subkey and segment subrange has this position's segment
|
// Lookup what subkey and segment subrange has this position's segment
|
||||||
// shortarray
|
// shortarray
|
||||||
final l = lookupSegment(segmentNumber);
|
final l = _lookupSegment(segmentNumber);
|
||||||
final subkey = l.subkey;
|
final subkey = l.subkey;
|
||||||
final segment = l.segment;
|
final segment = l.segment;
|
||||||
|
|
||||||
@ -304,7 +356,7 @@ class _DHTLogSpine {
|
|||||||
|
|
||||||
// Lookup what subkey and segment subrange has this position's segment
|
// Lookup what subkey and segment subrange has this position's segment
|
||||||
// shortarray
|
// shortarray
|
||||||
final l = lookupSegment(segmentNumber);
|
final l = _lookupSegment(segmentNumber);
|
||||||
final subkey = l.subkey;
|
final subkey = l.subkey;
|
||||||
final segment = l.segment;
|
final segment = l.segment;
|
||||||
|
|
||||||
@ -381,7 +433,7 @@ class _DHTLogSpine {
|
|||||||
return segment;
|
return segment;
|
||||||
}
|
}
|
||||||
|
|
||||||
_DHTLogSegmentLookup lookupSegment(int segmentNumber) {
|
_DHTLogSegmentLookup _lookupSegment(int segmentNumber) {
|
||||||
assert(_spineMutex.isLocked, 'should be in mutex here');
|
assert(_spineMutex.isLocked, 'should be in mutex here');
|
||||||
|
|
||||||
if (segmentNumber < 0) {
|
if (segmentNumber < 0) {
|
||||||
@ -400,9 +452,9 @@ class _DHTLogSpine {
|
|||||||
///////////////////////////////////////////
|
///////////////////////////////////////////
|
||||||
// API for public interfaces
|
// API for public interfaces
|
||||||
|
|
||||||
Future<DHTLogPositionLookup?> lookupPosition(int pos) async {
|
Future<_DHTLogPosition?> lookupPosition(int pos) async {
|
||||||
assert(_spineMutex.isLocked, 'should be locked');
|
assert(_spineMutex.isLocked, 'should be locked');
|
||||||
|
return _spineCacheMutex.protect(() async {
|
||||||
// Check if our position is in bounds
|
// Check if our position is in bounds
|
||||||
final endPos = length;
|
final endPos = length;
|
||||||
if (pos < 0 || pos >= endPos) {
|
if (pos < 0 || pos >= endPos) {
|
||||||
@ -417,13 +469,43 @@ class _DHTLogSpine {
|
|||||||
final segmentPos = absolutePosition % DHTShortArray.maxElements;
|
final segmentPos = absolutePosition % DHTShortArray.maxElements;
|
||||||
|
|
||||||
// Get the segment shortArray
|
// Get the segment shortArray
|
||||||
final shortArray = (_spineRecord.writer == null)
|
final openedSegment = _openedSegments[segmentNumber];
|
||||||
|
late final DHTShortArray shortArray;
|
||||||
|
if (openedSegment != null) {
|
||||||
|
openedSegment.openCount++;
|
||||||
|
shortArray = openedSegment.shortArray;
|
||||||
|
} else {
|
||||||
|
final newShortArray = (_spineRecord.writer == null)
|
||||||
? await _openSegment(segmentNumber)
|
? await _openSegment(segmentNumber)
|
||||||
: await _openOrCreateSegment(segmentNumber);
|
: await _openOrCreateSegment(segmentNumber);
|
||||||
if (shortArray == null) {
|
if (newShortArray == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return DHTLogPositionLookup(shortArray: shortArray, pos: segmentPos);
|
|
||||||
|
_openedSegments[segmentNumber] =
|
||||||
|
_OpenedSegment._(shortArray: newShortArray);
|
||||||
|
|
||||||
|
shortArray = newShortArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _DHTLogPosition._(
|
||||||
|
dhtLogSpine: this,
|
||||||
|
shortArray: shortArray,
|
||||||
|
pos: segmentPos,
|
||||||
|
segmentNumber: segmentNumber);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _segmentClosed(int segmentNumber) async {
|
||||||
|
assert(_spineMutex.isLocked, 'should be locked');
|
||||||
|
await _spineCacheMutex.protect(() async {
|
||||||
|
final os = _openedSegments[segmentNumber]!;
|
||||||
|
os.openCount--;
|
||||||
|
if (os.openCount == 0) {
|
||||||
|
_openedSegments.remove(segmentNumber);
|
||||||
|
await os.shortArray.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void allocateTail(int count) {
|
void allocateTail(int count) {
|
||||||
@ -479,7 +561,7 @@ class _DHTLogSpine {
|
|||||||
segmentNumber++) {
|
segmentNumber++) {
|
||||||
// Lookup what subkey and segment subrange has this position's segment
|
// Lookup what subkey and segment subrange has this position's segment
|
||||||
// shortarray
|
// shortarray
|
||||||
final l = lookupSegment(segmentNumber);
|
final l = _lookupSegment(segmentNumber);
|
||||||
final subkey = l.subkey;
|
final subkey = l.subkey;
|
||||||
final segment = l.segment;
|
final segment = l.segment;
|
||||||
|
|
||||||
@ -608,6 +690,8 @@ class _DHTLogSpine {
|
|||||||
|
|
||||||
// Spine DHT record
|
// Spine DHT record
|
||||||
final DHTRecord _spineRecord;
|
final DHTRecord _spineRecord;
|
||||||
|
// Segment stride to use for spine elements
|
||||||
|
final int _segmentStride;
|
||||||
|
|
||||||
// Position of the start of the log (oldest items)
|
// Position of the start of the log (oldest items)
|
||||||
int _head;
|
int _head;
|
||||||
@ -616,8 +700,8 @@ class _DHTLogSpine {
|
|||||||
|
|
||||||
// LRU cache of DHT spine elements accessed recently
|
// LRU cache of DHT spine elements accessed recently
|
||||||
// Pair of position and associated shortarray segment
|
// Pair of position and associated shortarray segment
|
||||||
|
final Mutex _spineCacheMutex = Mutex();
|
||||||
final List<(int, DHTShortArray)> _spineCache;
|
final List<(int, DHTShortArray)> _spineCache;
|
||||||
|
final Map<int, _OpenedSegment> _openedSegments;
|
||||||
static const int _spineCacheLength = 3;
|
static const int _spineCacheLength = 3;
|
||||||
// Segment stride to use for spine elements
|
|
||||||
final int _segmentStride;
|
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ enum DHTRecordRefreshMode {
|
|||||||
|
|
||||||
/////////////////////////////////////////////////
|
/////////////////////////////////////////////////
|
||||||
|
|
||||||
class DHTRecord implements DHTOpenable<DHTRecord> {
|
class DHTRecord implements DHTDeleteable<DHTRecord, DHTRecord> {
|
||||||
DHTRecord._(
|
DHTRecord._(
|
||||||
{required VeilidRoutingContext routingContext,
|
{required VeilidRoutingContext routingContext,
|
||||||
required SharedDHTRecordData sharedDHTRecordData,
|
required SharedDHTRecordData sharedDHTRecordData,
|
||||||
@ -52,12 +52,16 @@ class DHTRecord implements DHTOpenable<DHTRecord> {
|
|||||||
_sharedDHTRecordData = sharedDHTRecordData;
|
_sharedDHTRecordData = sharedDHTRecordData;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// DHTOpenable
|
// DHTCloseable
|
||||||
|
|
||||||
/// Check if the DHTRecord is open
|
/// Check if the DHTRecord is open
|
||||||
@override
|
@override
|
||||||
bool get isOpen => _openCount > 0;
|
bool get isOpen => _openCount > 0;
|
||||||
|
|
||||||
|
/// The type of the openable scope
|
||||||
|
@override
|
||||||
|
FutureOr<DHTRecord> scoped() => this;
|
||||||
|
|
||||||
/// Add a reference to this DHTRecord
|
/// Add a reference to this DHTRecord
|
||||||
@override
|
@override
|
||||||
Future<DHTRecord> ref() async => _mutex.protect(() async {
|
Future<DHTRecord> ref() async => _mutex.protect(() async {
|
||||||
|
@ -13,7 +13,7 @@ part 'dht_short_array_write.dart';
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class DHTShortArray implements DHTOpenable<DHTShortArray> {
|
class DHTShortArray implements DHTDeleteable<DHTShortArray, DHTShortArray> {
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
@ -136,12 +136,16 @@ class DHTShortArray implements DHTOpenable<DHTShortArray> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// DHTOpenable
|
// DHTCloseable
|
||||||
|
|
||||||
/// Check if the shortarray is open
|
/// Check if the shortarray is open
|
||||||
@override
|
@override
|
||||||
bool get isOpen => _openCount > 0;
|
bool get isOpen => _openCount > 0;
|
||||||
|
|
||||||
|
/// The type of the openable scope
|
||||||
|
@override
|
||||||
|
FutureOr<DHTShortArray> scoped() => this;
|
||||||
|
|
||||||
/// Add a reference to this shortarray
|
/// Add a reference to this shortarray
|
||||||
@override
|
@override
|
||||||
Future<DHTShortArray> ref() async => _mutex.protect(() async {
|
Future<DHTShortArray> ref() async => _mutex.protect(() async {
|
||||||
|
@ -1,27 +1,36 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
abstract class DHTOpenable<C> {
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
|
abstract class DHTCloseable<C, D> {
|
||||||
bool get isOpen;
|
bool get isOpen;
|
||||||
|
@protected
|
||||||
|
FutureOr<D> scoped();
|
||||||
Future<C> ref();
|
Future<C> ref();
|
||||||
Future<void> close();
|
Future<void> close();
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class DHTDeleteable<C, D> extends DHTCloseable<C, D> {
|
||||||
Future<void> delete();
|
Future<void> delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
extension DHTOpenableExt<D extends DHTOpenable<D>> on D {
|
extension DHTCloseableExt<C, D> on DHTCloseable<C, D> {
|
||||||
/// Runs a closure that guarantees the DHTOpenable
|
/// Runs a closure that guarantees the DHTCloseable
|
||||||
/// will be closed upon exit, even if an uncaught exception is thrown
|
/// will be closed upon exit, even if an uncaught exception is thrown
|
||||||
Future<T> scope<T>(Future<T> Function(D) scopeFunction) async {
|
Future<T> scope<T>(Future<T> Function(D) scopeFunction) async {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
throw StateError('not open in scope');
|
throw StateError('not open in scope');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return await scopeFunction(this);
|
return await scopeFunction(await scoped());
|
||||||
} finally {
|
} finally {
|
||||||
await close();
|
await close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Runs a closure that guarantees the DHTOpenable
|
extension DHTDeletableExt<C, D> on DHTDeleteable<C, D> {
|
||||||
|
/// Runs a closure that guarantees the DHTCloseable
|
||||||
/// will be closed upon exit, and deleted if an an
|
/// will be closed upon exit, and deleted if an an
|
||||||
/// uncaught exception is thrown
|
/// uncaught exception is thrown
|
||||||
Future<T> deleteScope<T>(Future<T> Function(D) scopeFunction) async {
|
Future<T> deleteScope<T>(Future<T> Function(D) scopeFunction) async {
|
||||||
@ -30,7 +39,7 @@ extension DHTOpenableExt<D extends DHTOpenable<D>> on D {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await scopeFunction(this);
|
return await scopeFunction(await scoped());
|
||||||
} on Exception {
|
} on Exception {
|
||||||
await delete();
|
await delete();
|
||||||
rethrow;
|
rethrow;
|
||||||
@ -39,7 +48,7 @@ extension DHTOpenableExt<D extends DHTOpenable<D>> on D {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scopes a closure that conditionally deletes the DHTOpenable on exit
|
/// Scopes a closure that conditionally deletes the DHTCloseable on exit
|
||||||
Future<T> maybeDeleteScope<T>(
|
Future<T> maybeDeleteScope<T>(
|
||||||
bool delete, Future<T> Function(D) scopeFunction) async {
|
bool delete, Future<T> Function(D) scopeFunction) async {
|
||||||
if (delete) {
|
if (delete) {
|
@ -1,4 +1,4 @@
|
|||||||
export 'dht_openable.dart';
|
export 'dht_closeable.dart';
|
||||||
export 'dht_random_read.dart';
|
export 'dht_random_read.dart';
|
||||||
export 'dht_random_write.dart';
|
export 'dht_random_write.dart';
|
||||||
export 'exceptions.dart';
|
export 'exceptions.dart';
|
||||||
|
Loading…
Reference in New Issue
Block a user