subchannel-pool.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. "use strict";
  2. /*
  3. * Copyright 2019 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. Object.defineProperty(exports, "__esModule", { value: true });
  19. exports.getSubchannelPool = exports.SubchannelPool = void 0;
  20. const channel_options_1 = require("./channel-options");
  21. const subchannel_1 = require("./subchannel");
  22. const subchannel_address_1 = require("./subchannel-address");
  23. const uri_parser_1 = require("./uri-parser");
  24. const transport_1 = require("./transport");
  25. // 10 seconds in milliseconds. This value is arbitrary.
  26. /**
  27. * The amount of time in between checks for dropping subchannels that have no
  28. * other references
  29. */
  30. const REF_CHECK_INTERVAL = 10000;
  31. class SubchannelPool {
  32. /**
  33. * A pool of subchannels use for making connections. Subchannels with the
  34. * exact same parameters will be reused.
  35. */
  36. constructor() {
  37. this.pool = Object.create(null);
  38. /**
  39. * A timer of a task performing a periodic subchannel cleanup.
  40. */
  41. this.cleanupTimer = null;
  42. }
  43. /**
  44. * Unrefs all unused subchannels and cancels the cleanup task if all
  45. * subchannels have been unrefed.
  46. */
  47. unrefUnusedSubchannels() {
  48. let allSubchannelsUnrefed = true;
  49. /* These objects are created with Object.create(null), so they do not
  50. * have a prototype, which means that for (... in ...) loops over them
  51. * do not need to be filtered */
  52. // eslint-disable-disable-next-line:forin
  53. for (const channelTarget in this.pool) {
  54. const subchannelObjArray = this.pool[channelTarget];
  55. const refedSubchannels = subchannelObjArray.filter(value => !value.subchannel.unrefIfOneRef());
  56. if (refedSubchannels.length > 0) {
  57. allSubchannelsUnrefed = false;
  58. }
  59. /* For each subchannel in the pool, try to unref it if it has
  60. * exactly one ref (which is the ref from the pool itself). If that
  61. * does happen, remove the subchannel from the pool */
  62. this.pool[channelTarget] = refedSubchannels;
  63. }
  64. /* Currently we do not delete keys with empty values. If that results
  65. * in significant memory usage we should change it. */
  66. // Cancel the cleanup task if all subchannels have been unrefed.
  67. if (allSubchannelsUnrefed && this.cleanupTimer !== null) {
  68. clearInterval(this.cleanupTimer);
  69. this.cleanupTimer = null;
  70. }
  71. }
  72. /**
  73. * Ensures that the cleanup task is spawned.
  74. */
  75. ensureCleanupTask() {
  76. var _a, _b;
  77. if (this.cleanupTimer === null) {
  78. this.cleanupTimer = setInterval(() => {
  79. this.unrefUnusedSubchannels();
  80. }, REF_CHECK_INTERVAL);
  81. // Unref because this timer should not keep the event loop running.
  82. // Call unref only if it exists to address electron/electron#21162
  83. (_b = (_a = this.cleanupTimer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
  84. }
  85. }
  86. /**
  87. * Get a subchannel if one already exists with exactly matching parameters.
  88. * Otherwise, create and save a subchannel with those parameters.
  89. * @param channelTarget
  90. * @param subchannelTarget
  91. * @param channelArguments
  92. * @param channelCredentials
  93. */
  94. getOrCreateSubchannel(channelTargetUri, subchannelTarget, channelArguments, channelCredentials) {
  95. this.ensureCleanupTask();
  96. const channelTarget = (0, uri_parser_1.uriToString)(channelTargetUri);
  97. if (channelTarget in this.pool) {
  98. const subchannelObjArray = this.pool[channelTarget];
  99. for (const subchannelObj of subchannelObjArray) {
  100. if ((0, subchannel_address_1.subchannelAddressEqual)(subchannelTarget, subchannelObj.subchannelAddress) &&
  101. (0, channel_options_1.channelOptionsEqual)(channelArguments, subchannelObj.channelArguments) &&
  102. channelCredentials._equals(subchannelObj.channelCredentials)) {
  103. return subchannelObj.subchannel;
  104. }
  105. }
  106. }
  107. // If we get here, no matching subchannel was found
  108. const subchannel = new subchannel_1.Subchannel(channelTargetUri, subchannelTarget, channelArguments, channelCredentials, new transport_1.Http2SubchannelConnector(channelTargetUri));
  109. if (!(channelTarget in this.pool)) {
  110. this.pool[channelTarget] = [];
  111. }
  112. this.pool[channelTarget].push({
  113. subchannelAddress: subchannelTarget,
  114. channelArguments,
  115. channelCredentials,
  116. subchannel,
  117. });
  118. subchannel.ref();
  119. return subchannel;
  120. }
  121. }
  122. exports.SubchannelPool = SubchannelPool;
  123. const globalSubchannelPool = new SubchannelPool();
  124. /**
  125. * Get either the global subchannel pool, or a new subchannel pool.
  126. * @param global
  127. */
  128. function getSubchannelPool(global) {
  129. if (global) {
  130. return globalSubchannelPool;
  131. }
  132. else {
  133. return new SubchannelPool();
  134. }
  135. }
  136. exports.getSubchannelPool = getSubchannelPool;
  137. //# sourceMappingURL=subchannel-pool.js.map