| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:collection'; |
| |
| import 'resource_record.dart'; |
| |
| /// Cache for resource records that have been received. |
| /// |
| /// There can be multiple entries for the same name and type. |
| /// |
| /// The cache is updated with a list of records, because it needs to remove |
| /// all entries that correspond to the name and type of the name/type |
| /// combinations of records that should be updated. For example, a host may |
| /// remove one of its IP addresses and report the remaining address as a |
| /// response - then we need to clear all previous entries for that host before |
| /// updating the cache. |
| class ResourceRecordCache { |
| /// Creates a new ResourceRecordCache. |
| ResourceRecordCache(); |
| |
| final Map<int, SplayTreeMap<String, List<ResourceRecord>>> _cache = |
| <int, SplayTreeMap<String, List<ResourceRecord>>>{}; |
| |
| /// The number of entries in the cache. |
| int get entryCount { |
| int count = 0; |
| for (final SplayTreeMap<String, List<ResourceRecord>> map |
| in _cache.values) { |
| for (final List<ResourceRecord> records in map.values) { |
| count += records.length; |
| } |
| } |
| return count; |
| } |
| |
| /// Update the records in this cache. |
| void updateRecords(List<ResourceRecord> records) { |
| // TODO(karlklose): include flush bit in the record and only flush if |
| // necessary. |
| // Clear the cache for all name/type combinations to be updated. |
| final Map<int, Set<String>> seenRecordTypes = <int, Set<String>>{}; |
| for (final ResourceRecord record in records) { |
| // TODO(dnfield): Update this to use set literal syntax when we're able to bump the SDK constraint. |
| seenRecordTypes[record.resourceRecordType] ??= |
| Set<String>(); // ignore: prefer_collection_literals |
| if (seenRecordTypes[record.resourceRecordType]!.add(record.name)) { |
| _cache[record.resourceRecordType] ??= |
| SplayTreeMap<String, List<ResourceRecord>>(); |
| |
| _cache[record.resourceRecordType]![record.name] = <ResourceRecord>[ |
| record |
| ]; |
| } else { |
| _cache[record.resourceRecordType]![record.name]!.add(record); |
| } |
| } |
| } |
| |
| /// Get a record from this cache. |
| void lookup<T extends ResourceRecord>( |
| String name, int type, List<T> results) { |
| assert(ResourceRecordType.debugAssertValid(type)); |
| final int time = DateTime.now().millisecondsSinceEpoch; |
| final SplayTreeMap<String, List<ResourceRecord>>? candidates = _cache[type]; |
| if (candidates == null) { |
| return; |
| } |
| |
| final List<ResourceRecord>? candidateRecords = candidates[name]; |
| if (candidateRecords == null) { |
| return; |
| } |
| candidateRecords |
| .removeWhere((ResourceRecord candidate) => candidate.validUntil < time); |
| results.addAll(candidateRecords.cast<T>()); |
| } |
| } |