| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library pub_dartlang_org.package_memcache; | 5 library pub_dartlang_org.package_memcache; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:convert'; | 8 import 'dart:convert'; |
| 9 | 9 |
| 10 import 'package:logging/logging.dart'; | 10 import 'package:logging/logging.dart'; |
| 11 import 'package:memcache/memcache.dart'; | 11 import 'package:memcache/memcache.dart'; |
| 12 import 'package:pub_server/shelf_pubserver.dart'; | 12 import 'package:pub_server/shelf_pubserver.dart'; |
| 13 | 13 |
| 14 final Logger _logger = new Logger('pub.package_memcache'); | 14 final Logger _logger = new Logger('pub.package_memcache'); |
| 15 | 15 |
| 16 abstract class UIPackageCache { | 16 abstract class UIPackageCache { |
| 17 Future<String> getUIPackagePage(String package); | 17 // If [version] is `null` then it corresponds to the cache entry which can be |
| 18 // invalidated via [invalidateUiPackagePage]. |
| 19 Future<String> getUIPackagePage(String package, String version); |
| 18 | 20 |
| 19 Future setUIPackagePage(String package, String data); | 21 // If [version] is `null` then it corresponds to the cache entry which can be |
| 22 // invalidated via [invalidateUiPackagePage]. |
| 23 Future setUIPackagePage(String package, String version, String data); |
| 20 | 24 |
| 21 Future invalidateUIPackagePage(String package); | 25 Future invalidateUIPackagePage(String package); |
| 22 } | 26 } |
| 23 | 27 |
| 24 /// Uses a [Memache] to set/get/invalidate metadata for packages. | 28 /// Uses a [Memache] to set/get/invalidate metadata for packages. |
| 25 class AppEnginePackageMemcache implements PackageCache, UIPackageCache { | 29 class AppEnginePackageMemcache implements PackageCache, UIPackageCache { |
| 26 static const Duration EXPIRATION = const Duration(minutes: 60); | 30 static const Duration EXPIRATION = const Duration(minutes: 60); |
| 27 static const String KEY_PREFIX = 'dart_package_json'; | 31 static const String KEY_PREFIX = 'dart_package_json'; |
| 28 static const String UI_KEY_PREFIX = 'dart_package_ui'; | 32 static const String UI_KEY_PREFIX = 'dart_package_ui'; |
| 29 | 33 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 46 | 50 |
| 47 return result; | 51 return result; |
| 48 } | 52 } |
| 49 | 53 |
| 50 Future setPackageData(String package, List<int> data) { | 54 Future setPackageData(String package, List<int> data) { |
| 51 _logger.info('memcache["$package"] setting to new data'); | 55 _logger.info('memcache["$package"] setting to new data'); |
| 52 return _ignoreErrors( | 56 return _ignoreErrors( |
| 53 memcache.set(_packageKey(package), data, expiration: EXPIRATION)); | 57 memcache.set(_packageKey(package), data, expiration: EXPIRATION)); |
| 54 } | 58 } |
| 55 | 59 |
| 56 Future<String> getUIPackagePage(String package) async { | 60 Future<String> getUIPackagePage(String package, String version) async { |
| 57 var result = await _ignoreErrors( | 61 var result = await _ignoreErrors( |
| 58 memcache.get(_packageUIKey(package), asBinary: true)); | 62 memcache.get(_packageUIKey(package, version), asBinary: true)); |
| 59 | 63 |
| 60 if (result != null) { | 64 if (result != null) { |
| 61 _logger.info('memcache["$package"] rendered UI found'); | 65 _logger.info('memcache["$package"] rendered UI found'); |
| 62 return UTF8.decode(result); | 66 return UTF8.decode(result); |
| 63 } | 67 } |
| 64 | 68 |
| 65 _logger.info('memcache["$package"] rendered UI not found'); | 69 _logger.info('memcache["$package"] rendered UI not found'); |
| 66 return null; | 70 return null; |
| 67 } | 71 } |
| 68 | 72 |
| 69 Future setUIPackagePage(String package, String data) async { | 73 Future setUIPackagePage(String package, String version, String data) async { |
| 70 _logger.info('memcache["$package"] setting to new rendered UI data'); | 74 _logger.info('memcache["$package"] setting to new rendered UI data'); |
| 71 return _ignoreErrors( | 75 return _ignoreErrors( |
| 72 memcache.set(_packageUIKey(package), | 76 memcache.set(_packageUIKey(package, version), |
| 73 UTF8.encode(data), | 77 UTF8.encode(data), |
| 74 expiration: EXPIRATION)); | 78 expiration: EXPIRATION)); |
| 75 } | 79 } |
| 76 | 80 |
| 77 Future invalidateUIPackagePage(String package) async { | 81 Future invalidateUIPackagePage(String package) async { |
| 78 _logger.info('memcache["$package"] invalidating UI data'); | 82 _logger.info('memcache["$package"] invalidating UI data'); |
| 79 return _ignoreErrors(memcache.remove(_packageUIKey(package))); | 83 return _ignoreErrors(memcache.remove(_packageUIKey(package, null))); |
| 80 } | 84 } |
| 81 | 85 |
| 82 Future invalidatePackageData(String package) { | 86 Future invalidatePackageData(String package) { |
| 83 _logger.info('memcache["$package"] invalidate entry'); | 87 _logger.info('memcache["$package"] invalidate entry'); |
| 84 return _ignoreErrors(Future.wait([ | 88 return _ignoreErrors(Future.wait([ |
| 85 // TODO: Once the Python version is retired, we can remove this. | 89 // TODO: Once the Python version is retired, we can remove this. |
| 86 memcache.remove('package_json_$package'), | 90 memcache.remove('package_json_$package'), |
| 87 memcache.remove(_packageKey(package)), | 91 memcache.remove(_packageKey(package)), |
| 88 memcache.remove(_packageUIKey(package)), | 92 memcache.remove(_packageUIKey(package, null)), |
| 89 ])); | 93 ])); |
| 90 } | 94 } |
| 91 | 95 |
| 92 String _packageKey(String package) => '$keyPrefix$package'; | 96 String _packageKey(String package) => '$keyPrefix$package'; |
| 93 | 97 |
| 94 String _packageUIKey(String package) => '$uiKeyPrefix$package'; | 98 String _packageUIKey(String package, String version) { |
| 99 if (version == null) return '$uiKeyPrefix$package'; |
| 100 return '$uiKeyPrefix$package**$version'; |
| 101 } |
| 95 | 102 |
| 96 // We are ignoring any memcache errors and just return `null` in this case. | 103 // We are ignoring any memcache errors and just return `null` in this case. |
| 97 // | 104 // |
| 98 // NOTE: The worst what can happen is that up to `EXPIRATION` time passes | 105 // NOTE: The worst what can happen is that up to `EXPIRATION` time passes |
| 99 // before a value gets automatically evicted from memcache | 106 // before a value gets automatically evicted from memcache |
| 100 // => The duration for inconsistency is limited to 60 minutes ATM. | 107 // => The duration for inconsistency is limited to 60 minutes ATM. |
| 101 Future _ignoreErrors(Future f) { | 108 Future _ignoreErrors(Future f) { |
| 102 return f.catchError((error, stackTrace) { | 109 return f.catchError((error, stackTrace) { |
| 103 _logger.warning( | 110 _logger.warning( |
| 104 'Ignoring failed memcache API call (error: $error)', | 111 'Ignoring failed memcache API call (error: $error)', |
| 105 error, stackTrace); | 112 error, stackTrace); |
| 106 }); | 113 }); |
| 107 } | 114 } |
| 108 } | 115 } |
| OLD | NEW |