dart-sdk/sdk/lib/vmservice/named_lookup.dart
Vyacheslav Egorov b2eab8b96e [VM/Service] Restore zero-copying handling of JSON messages in vmservice.
In 5a44162c97 in attempt to adhere to declared
method signatures we lost zero-copying JSON decoding of responses from
VM: `Message.sendToVM` was changed to always decode the response into
string before passing it to the caller and the logic to use fused
JSON decoding was removed. This increased peak memory consumption by
the VM Service.

This commit addresses the issue by restoring the zero-copying JSON decoding
logic while adding a wrapper around responses that make it clear what kind
of data is passed around and how that data is encoded and handled.

We introduce a class `Response` which can contain either a Dart string, a
binary data (represented as a Uint8List) or utf8 encoded string (represented
as a Uint8List). This class is used in all places where previously a String
or dynamic were used, e.g. MessageRouter.routeRequest is changed to return
Future<Response> rather than Future<String>. This allows callees to
decode JSON responses without copying them into Dart heap while
maintaining sufficient level of typing to make the code easy to reason about.

This commit also removes some dead code from the VM service related to old
Service API and TAR assets unpacking (which has been long done in C++).

Bug: https://github.com/flutter/flutter/issues/13626
Change-Id: Ifbba56944a552034a0f802a965a313326a1236e7
Reviewed-on: https://dart-review.googlesource.com/30280
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
2017-12-18 19:06:06 +00:00

69 lines
1.7 KiB
Dart

// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart._vmservice;
/// Set like containes which automatically generated String ids for its items
class NamedLookup<E> extends Object with IterableMixin<E> {
final IdGenerator _generator;
final Map<String, E> _elements = new Map<String, E>();
final Map<E, String> _ids = new Map<E, String>();
NamedLookup({String prologue = ''})
: _generator = new IdGenerator(prologue: prologue);
void add(E e) {
final id = _generator.newId();
_elements[id] = e;
_ids[e] = id;
}
void remove(E e) {
final id = _ids.remove(e);
_elements.remove(id);
_generator.release(id);
}
E operator [](String id) => _elements[id];
String keyOf(E e) => _ids[e];
Iterator<E> get iterator => _ids.keys.iterator;
}
/// Generator for unique ids which recycles expired ones
class IdGenerator {
/// Fixed initial part of the id
final String prologue;
// Ids in use
final Set<String> _used = new Set<String>();
/// Ids that has been released (use these before generate new ones)
final Set<String> _free = new Set<String>();
/// Next id to generate if no one can be recycled (first use _free);
int _next = 0;
IdGenerator({this.prologue = ''});
/// Returns a new Id (possibly recycled)
String newId() {
var id;
if (_free.isEmpty) {
id = prologue + (_next++).toString();
} else {
id = _free.first;
}
_free.remove(id);
_used.add(id);
return id;
}
/// Releases the id and mark it for recycle
void release(String id) {
if (_used.remove(id)) {
_free.add(id);
}
}
}