Skip to content

Commit

Permalink
Merge v1.0.10 - async-call-cache
Browse files Browse the repository at this point in the history
 - `SharedMapCached`:
   - Introduces async call caching for `get`, `keys`, `values`, `entries` and `length` operations,
     to avoid simultaneous asynchronous calls (fetching) for the same operation. 

 - `SharedStoreIsolateServer`:
   - Fix  call to `getSharedMap<K,V>()` with correct `K` and `V` casting when requested by `SharedStoreIsolateClient`.

 - Improve `SharedMap.toString` implementations.
  • Loading branch information
gmpassos committed Nov 24, 2023
2 parents c6b5f7c + 1da9297 commit 49914e5
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 20 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## 1.0.10

- `SharedMapCached`:
- Introduces async call caching for `get`, `keys`, `values`, `entries` and `length` operations,
to avoid simultaneous asynchronous calls (fetching) for the same operation.

- `SharedStoreIsolateServer`:
- Fix call to `getSharedMap<K,V>()` with correct `K` and `V` casting when requested by `SharedStoreIsolateClient`.

- Improve `SharedMap.toString` implementations.

## 1.0.9

- `SharedMap`:
Expand Down
5 changes: 5 additions & 0 deletions lib/src/not_shared_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ class NotSharedMap<K, V> implements SharedMapSync<K, V> {
@override
SharedMapReference sharedReference() =>
_sharedReference ??= NotSharedMapReference(this);

@override
String toString() {
return 'NotSharedMap<$K,$V>[$id@${sharedStore.id}]{entries: ${_entries.length}}';
}
}

class NotSharedStoreReference extends SharedStoreReference {
Expand Down
81 changes: 72 additions & 9 deletions lib/src/shared_map_cached.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,23 +75,38 @@ class SharedMapCached<K, V> implements SharedMap<K, V> {
}
}

var getAsync = _getAsync;
if (getAsync != null) {
return getAsync;
}

var val = _sharedMap.get(key);
return _cacheValue(key, val, now);
}

Future<V?>? _getAsync;

FutureOr<V?> _cacheValue(K key, FutureOr<V?> value, DateTime now) {
if (value is Future<V?>) {
return value.then((value) {
return _getAsync = value.then((value) {
if (value != null) {
_cache[key] = (now, value);
}
_getAsync = null;
return value;
}, onError: (e) {
_getAsync = null;
throw e;
});
} else if (value != null) {
_cache[key] = (now, value);
return value;
} else {
return null;
_getAsync = null;

if (value != null) {
_cache[key] = (now, value);
return value;
} else {
return null;
}
}
}

Expand Down Expand Up @@ -143,18 +158,30 @@ class SharedMapCached<K, V> implements SharedMap<K, V> {
}
}

var keysAsync = _keysAsync;
if (keysAsync != null) {
return keysAsync;
}

var keys = _sharedMap.keys();
return _cacheKeys(keys, now);
}

Future<List<K>>? _keysAsync;

FutureOr<List<K>> _cacheKeys(FutureOr<List<K>> keys, DateTime now) {
if (keys is Future<List<K>>) {
return keys.then((keys) {
return _keysAsync = keys.then((keys) {
_keysCached = (now, keys);
_keysAsync = null;
return keys;
}, onError: (e) {
_keysAsync = null;
throw e;
});
} else {
_keysCached = (now, keys);
_keysAsync = null;
return keys;
}
}
Expand All @@ -180,18 +207,30 @@ class SharedMapCached<K, V> implements SharedMap<K, V> {
}
}

var valuesAsync = _valuesAsync;
if (valuesAsync != null) {
return valuesAsync;
}

var values = _sharedMap.values();
return _cacheValues(values, now);
}

Future<List<V>>? _valuesAsync;

FutureOr<List<V>> _cacheValues(FutureOr<List<V>> values, DateTime now) {
if (values is Future<List<V>>) {
return values.then((values) {
return _valuesAsync = values.then((values) {
_valuesCached = (now, values);
_valuesAsync = null;
return values;
}, onError: (e) {
_valuesAsync = null;
throw e;
});
} else {
_valuesCached = (now, values);
_valuesAsync = null;
return values;
}
}
Expand All @@ -218,19 +257,31 @@ class SharedMapCached<K, V> implements SharedMap<K, V> {
}
}

var entriesAsync = _entriesAsync;
if (entriesAsync != null) {
return entriesAsync;
}

var entries = _sharedMap.entries();
return _cacheEntries(entries, now);
}

Future<List<MapEntry<K, V>>>? _entriesAsync;

FutureOr<List<MapEntry<K, V>>> _cacheEntries(
FutureOr<List<MapEntry<K, V>>> entries, DateTime now) {
if (entries is Future<List<MapEntry<K, V>>>) {
return entries.then((values) {
return _entriesAsync = entries.then((values) {
_entriesCached = (now, values);
_entriesAsync = null;
return values;
}, onError: (e) {
_entriesAsync = null;
throw e;
});
} else {
_entriesCached = (now, entries);
_entriesAsync = null;
return entries;
}
}
Expand Down Expand Up @@ -260,18 +311,30 @@ class SharedMapCached<K, V> implements SharedMap<K, V> {
}
}

var lengthAsync = _lengthAsync;
if (lengthAsync != null) {
return lengthAsync;
}

var length = _sharedMap.length();
return _cacheKeysLength(length, now);
}

Future<int>? _lengthAsync;

FutureOr<int> _cacheKeysLength(FutureOr<int> length, DateTime now) {
if (length is Future<int>) {
return length.then((length) {
return _lengthAsync = length.then((length) {
_keysLengthCached = (now, length);
_lengthAsync = null;
return length;
}, onError: (e) {
_lengthAsync = null;
throw e;
});
} else {
_keysLengthCached = (now, length);
_lengthAsync = null;
return length;
}
}
Expand Down
7 changes: 6 additions & 1 deletion lib/src/shared_map_generic.dart
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,11 @@ class SharedMapGeneric<K, V> implements SharedMapSync<K, V> {

@override
SharedMapCached<K, V> cached({Duration? timeout}) => _cached;

@override
String toString() {
return 'SharedMapGeneric<$K,$V>[$id@${sharedStore.id}]{entries: ${_entries.length}}';
}
}

/// A fake implementation (not cached) of [SharedMapCached].
Expand Down Expand Up @@ -266,7 +271,7 @@ class SharedMapCacheGeneric<K, V> implements SharedMapCached<K, V> {

@override
String toString() =>
'SharedMapCachedGeneric[$id@${sharedStore.id}]{timeout: $timeout}->$_sharedMap';
'SharedMapCachedGeneric<$K,$V>[$id@${sharedStore.id}]{timeout: $timeout}->$_sharedMap';
}

class SharedStoreReferenceGeneric extends SharedStoreReference {
Expand Down
30 changes: 24 additions & 6 deletions lib/src/shared_map_isolate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ class SharedStoreIsolateServer extends SharedStoreIsolate {
var clientPort = m[0] as SendPort;
var messageID = m[1] as int;
var id = m[2] as String;
var callCasted = m[3] as _CallCasted;

var sharedMap = _sharedMaps[id];
var sharedMap =
callCasted(<K1, V1>() => getSharedMap<K1, V1>(id)) as SharedMap?;

clientPort.send([messageID, sharedMap?.sharedReference()]);
return;
Expand All @@ -56,13 +58,17 @@ class SharedStoreIsolateServer extends SharedStoreIsolate {
}

@override
FutureOr<SharedMap<K, V>?> getSharedMap<K, V>(
SharedMap<K, V>? getSharedMap<K, V>(
String id, {
SharedMapEntryCallback<K, V>? onPut,
SharedMapEntryCallback<K, V>? onRemove,
}) {
var sharedMap = _sharedMaps[id];
if (sharedMap != null) {
if (sharedMap is! SharedMap<K, V>) {
throw StateError(
"[$this] Can't cast `sharedMap` to `SharedMap<$K, $V>`: $sharedMap");
}
return sharedMap as SharedMap<K, V>;
}

Expand All @@ -82,6 +88,8 @@ class SharedStoreIsolateServer extends SharedStoreIsolate {
'SharedStoreIsolateServer[$id]{sharedMaps: ${_sharedMaps.length}}';
}

typedef _CallCasted<K, V> = Object? Function(Object? Function<K1, V1>() f);

class SharedStoreIsolateClient extends SharedStoreIsolate {
final SendPort _serverPort;

Expand Down Expand Up @@ -125,15 +133,25 @@ class SharedStoreIsolateClient extends SharedStoreIsolate {
var msgID = ++_msgIDCounter;
var completer = _waitingResponse[msgID] = Completer();

_serverPort.send([_receivePort.sendPort, msgID, id]);
_CallCasted<K, V> callCasted = _buildCallCasted<K, V>();

_serverPort.send([_receivePort.sendPort, msgID, id, callCasted]);

return completer.future.then((ref) {
var o = createSharedMap<K, V>(sharedReference: ref!);
if (ref == null) {
throw StateError(
"Can't get `SharedMap` `SendPort` from \"server\" instance: $id");
}
var o = createSharedMap<K, V>(sharedReference: ref);
o.setCallbacksDynamic<K, V>(onPut: onPut, onRemove: onRemove);
return o;
});
}

/// Generates the lambda [Function] that will be passed to the
/// [SharedMapIsolateServer] to allow the correct casted call to [getSharedMap]`<K,V>()`.
_CallCasted<K, V> _buildCallCasted<K, V>() => (f) => f<K, V>();

@override
SharedStoreReferenceIsolate sharedReference() =>
SharedStoreReferenceIsolate(id, _serverPort);
Expand Down Expand Up @@ -356,7 +374,7 @@ class SharedMapIsolateServer<K, V> extends SharedMapIsolate<K, V>

@override
String toString() =>
'SharedMapIsolateServer[$id@${sharedStore.id}]{entries: ${_entries.length}';
'SharedMapIsolateServer<$K,$V>[$id@${sharedStore.id}]{entries: ${_entries.length}}';
}

class SharedMapIsolateClient<K, V> extends SharedMapIsolate<K, V>
Expand Down Expand Up @@ -518,7 +536,7 @@ class SharedMapIsolateClient<K, V> extends SharedMapIsolate<K, V>
SharedMapReferenceIsolate(id, sharedStore.sharedReference(), _serverPort);

@override
String toString() => 'SharedMapIsolateClient[$id@${sharedStore.id}]';
String toString() => 'SharedMapIsolateClient<$K,$V>[$id@${sharedStore.id}]';
}

class SharedStoreReferenceIsolate extends SharedStoreReference {
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: shared_map
description: Offers a versatile, synchronized Map for efficient sharing between Dart application parts, including Isolates or external apps.
version: 1.0.9
version: 1.0.10
repository: https://github.com/gmpassos/shared_map

environment:
Expand Down

0 comments on commit 49914e5

Please sign in to comment.