subchannel-pool.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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. // 10 seconds in milliseconds. This value is arbitrary.
  25. /**
  26. * The amount of time in between checks for dropping subchannels that have no
  27. * other references
  28. */
  29. const REF_CHECK_INTERVAL = 10000;
  30. class SubchannelPool {
  31. /**
  32. * A pool of subchannels use for making connections. Subchannels with the
  33. * exact same parameters will be reused.
  34. */
  35. constructor() {
  36. this.pool = Object.create(null);
  37. /**
  38. * A timer of a task performing a periodic subchannel cleanup.
  39. */
  40. this.cleanupTimer = null;
  41. }
  42. /**
  43. * Unrefs all unused subchannels and cancels the cleanup task if all
  44. * subchannels have been unrefed.
  45. */
  46. unrefUnusedSubchannels() {
  47. let allSubchannelsUnrefed = true;
  48. /* These objects are created with Object.create(null), so they do not
  49. * have a prototype, which means that for (... in ...) loops over them
  50. * do not need to be filtered */
  51. // eslint-disable-disable-next-line:forin
  52. for (const channelTarget in this.pool) {
  53. const subchannelObjArray = this.pool[channelTarget];
  54. const refedSubchannels = subchannelObjArray.filter((value) => !value.subchannel.unrefIfOneRef());
  55. if (refedSubchannels.length > 0) {
  56. allSubchannelsUnrefed = false;
  57. }
  58. /* For each subchannel in the pool, try to unref it if it has
  59. * exactly one ref (which is the ref from the pool itself). If that
  60. * does happen, remove the subchannel from the pool */
  61. this.pool[channelTarget] = refedSubchannels;
  62. }
  63. /* Currently we do not delete keys with empty values. If that results
  64. * in significant memory usage we should change it. */
  65. // Cancel the cleanup task if all subchannels have been unrefed.
  66. if (allSubchannelsUnrefed && this.cleanupTimer !== null) {
  67. clearInterval(this.cleanupTimer);
  68. this.cleanupTimer = null;
  69. }
  70. }
  71. /**
  72. * Ensures that the cleanup task is spawned.
  73. */
  74. ensureCleanupTask() {
  75. var _a, _b;
  76. if (this.cleanupTimer === null) {
  77. this.cleanupTimer = setInterval(() => {
  78. this.unrefUnusedSubchannels();
  79. }, REF_CHECK_INTERVAL);
  80. // Unref because this timer should not keep the event loop running.
  81. // Call unref only if it exists to address electron/electron#21162
  82. (_b = (_a = this.cleanupTimer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
  83. }
  84. }
  85. /**
  86. * Get a subchannel if one already exists with exactly matching parameters.
  87. * Otherwise, create and save a subchannel with those parameters.
  88. * @param channelTarget
  89. * @param subchannelTarget
  90. * @param channelArguments
  91. * @param channelCredentials
  92. */
  93. getOrCreateSubchannel(channelTargetUri, subchannelTarget, channelArguments, channelCredentials) {
  94. this.ensureCleanupTask();
  95. const channelTarget = uri_parser_1.uriToString(channelTargetUri);
  96. if (channelTarget in this.pool) {
  97. const subchannelObjArray = this.pool[channelTarget];
  98. for (const subchannelObj of subchannelObjArray) {
  99. if (subchannel_address_1.subchannelAddressEqual(subchannelTarget, subchannelObj.subchannelAddress) &&
  100. channel_options_1.channelOptionsEqual(channelArguments, subchannelObj.channelArguments) &&
  101. channelCredentials._equals(subchannelObj.channelCredentials)) {
  102. return subchannelObj.subchannel;
  103. }
  104. }
  105. }
  106. // If we get here, no matching subchannel was found
  107. const subchannel = new subchannel_1.Subchannel(channelTargetUri, subchannelTarget, channelArguments, channelCredentials);
  108. if (!(channelTarget in this.pool)) {
  109. this.pool[channelTarget] = [];
  110. }
  111. this.pool[channelTarget].push({
  112. subchannelAddress: subchannelTarget,
  113. channelArguments,
  114. channelCredentials,
  115. subchannel,
  116. });
  117. subchannel.ref();
  118. return subchannel;
  119. }
  120. }
  121. exports.SubchannelPool = SubchannelPool;
  122. const globalSubchannelPool = new SubchannelPool();
  123. /**
  124. * Get either the global subchannel pool, or a new subchannel pool.
  125. * @param global
  126. */
  127. function getSubchannelPool(global) {
  128. if (global) {
  129. return globalSubchannelPool;
  130. }
  131. else {
  132. return new SubchannelPool();
  133. }
  134. }
  135. exports.getSubchannelPool = getSubchannelPool;
  136. //# sourceMappingURL=subchannel-pool.js.map