{"action":"created","comment":{"url":"https://api.github.com/repos/infinispan/infinispan/pulls/comments/35649665","id":35649665,"diff_hunk":"@@ -0,0 +1,95 @@\n+package org.infinispan.stream.impl.termop;\n+\n+import org.infinispan.container.entries.CacheEntry;\n+import org.infinispan.container.entries.ImmortalCacheEntry;\n+import org.infinispan.stream.impl.KeyTrackingTerminalOperation;\n+import org.infinispan.stream.impl.intops.IntermediateOperation;\n+import org.infinispan.stream.impl.termop.object.NoMapIteratorOperation;\n+\n+import java.util.ArrayList;\n+import java.util.Collection;\n+import java.util.List;\n+import java.util.Map;\n+import java.util.Set;\n+import java.util.function.Supplier;\n+import java.util.stream.BaseStream;\n+import java.util.stream.Stream;\n+\n+/**\n+ * This is a base operation class for the use of the for each terminal operator.  This class can be used for any\n+ * forEach configuration, however since it relies on generics it may not be as performant as a primitive based\n+ * for each operation.\n+ * This class assumes the stream is composed of {@link java.util.Map.Entry} instances where the key is typed the same\n+ * as defined K type.\n+ * @param <K> key type of underlying stream\n+ * @param <V> value type of transformed stream\n+ * @param <S> type of the transformed stream\n+ */\n+public abstract class AbstractForEachOperation<K, V, S extends BaseStream<V, S>> extends BaseTerminalOperation\n+        implements KeyTrackingTerminalOperation<K, V, K> {\n+   private final int batchSize;\n+\n+   public AbstractForEachOperation(Iterable<IntermediateOperation> intermediateOperations,\n+           Supplier<Stream<CacheEntry>> supplier, int batchSize) {\n+      super(intermediateOperations, supplier);\n+      this.batchSize = batchSize;\n+   }\n+\n+   @Override\n+   public boolean lostSegment(boolean stopIfLost) {\n+      // TODO: stop this early\n+      return true;\n+   }\n+\n+   @Override\n+   public List<V> performOperation(IntermediateCollector<Collection<V>> response) {\n+      /**\n+       * This is for rehash only! {@link SingleRunOperation} should always be used for non rehash for each\n+       */\n+      throw new UnsupportedOperationException();\n+   }\n+\n+   protected abstract void handleList(List<V> list);\n+\n+   protected abstract void handleStreamForEach(S stream, List<V> list);\n+\n+   @Override\n+   public Collection<CacheEntry<K, K>> performOperationRehashAware(\n+           IntermediateCollector<Collection<CacheEntry<K, K>>> response) {\n+      // We only support sequential streams for iterator rehash aware\n+      BaseStream<?, ?> stream = supplier.get().sequential();\n+\n+      List<CacheEntry<K, K>> collectedValues = new ArrayList(batchSize);\n+\n+      List<V> currentList = new ArrayList<>();\n+      Object[] currentKey = new Object[1];\n+      stream = ((Stream<Map.Entry<K, ?>>) stream).peek(e -> {\n+         if (!currentList.isEmpty()) {\n+            collectedValues.add(new ImmortalCacheEntry(currentKey[0], currentKey[0]));\n+            if (collectedValues.size() >= batchSize) {\n+               handleList(currentList);\n+               response.sendDataResonse(collectedValues);\n+               collectedValues.clear();\n+               currentList.clear();\n+            }\n+         }\n+         currentKey[0] = e.getKey();\n+      });\n+      for (IntermediateOperation intermediateOperation : intermediateOperations) {\n+         stream = intermediateOperation.perform(stream);\n+      }\n+\n+      S convertedStream = ((S) stream);\n+      // We rely on the fact that iterator processes 1 entry at a time\n+      handleStreamForEach(convertedStream, currentList);\n+      if (!currentList.isEmpty()) {\n+         handleList(currentList);\n+         collectedValues.add(new ImmortalCacheEntry(currentKey[0], currentKey[0]));","path":"core/src/main/java/org/infinispan/stream/impl/termop/AbstractForEachOperation.java","position":87,"original_position":87,"commit_id":"7c7b0639b93aa0f7ce1a0c21a28f6b065508c5f6","original_commit_id":"7c7b0639b93aa0f7ce1a0c21a28f6b065508c5f6","user":{"login":"wburns","id":648175,"avatar_url":"https://avatars.githubusercontent.com/u/648175?v=3","gravatar_id":"","url":"https://api.github.com/users/wburns","html_url":"https://github.com/wburns","followers_url":"https://api.github.com/users/wburns/followers","following_url":"https://api.github.com/users/wburns/following{/other_user}","gists_url":"https://api.github.com/users/wburns/gists{/gist_id}","starred_url":"https://api.github.com/users/wburns/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wburns/subscriptions","organizations_url":"https://api.github.com/users/wburns/orgs","repos_url":"https://api.github.com/users/wburns/repos","events_url":"https://api.github.com/users/wburns/events{/privacy}","received_events_url":"https://api.github.com/users/wburns/received_events","type":"User","site_admin":false},"body":"And actually this may be a copy pasta mistake.  I have to look closer, but forEach shouldn't require a value, only the key, for rehash aware operations.","created_at":"2015-07-28T13:56:30Z","updated_at":"2015-07-28T13:56:30Z","html_url":"https://github.com/infinispan/infinispan/pull/3569#discussion_r35649665","pull_request_url":"https://api.github.com/repos/infinispan/infinispan/pulls/3569","_links":{"self":{"href":"https://api.github.com/repos/infinispan/infinispan/pulls/comments/35649665"},"html":{"href":"https://github.com/infinispan/infinispan/pull/3569#discussion_r35649665"},"pull_request":{"href":"https://api.github.com/repos/infinispan/infinispan/pulls/3569"}}},"pull_request":{"url":"https://api.github.com/repos/infinispan/infinispan/pulls/3569","id":39024823,"html_url":"https://github.com/infinispan/infinispan/pull/3569","diff_url":"https://github.com/infinispan/infinispan/pull/3569.diff","patch_url":"https://github.com/infinispan/infinispan/pull/3569.patch","issue_url":"https://api.github.com/repos/infinispan/infinispan/issues/3569","number":3569,"state":"closed","locked":false,"title":"Ispn 5293 Distributed Streams","user":{"login":"wburns","id":648175,"avatar_url":"https://avatars.githubusercontent.com/u/648175?v=3","gravatar_id":"","url":"https://api.github.com/users/wburns","html_url":"https://github.com/wburns","followers_url":"https://api.github.com/users/wburns/followers","following_url":"https://api.github.com/users/wburns/following{/other_user}","gists_url":"https://api.github.com/users/wburns/gists{/gist_id}","starred_url":"https://api.github.com/users/wburns/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wburns/subscriptions","organizations_url":"https://api.github.com/users/wburns/orgs","repos_url":"https://api.github.com/users/wburns/repos","events_url":"https://api.github.com/users/wburns/events{/privacy}","received_events_url":"https://api.github.com/users/wburns/received_events","type":"User","site_admin":false},"body":"There are still some missing pieces listed here (TODOs may contain others) - however most of these are not showstoppers but will be required later for additional functionality that may rely on this feature.\r\n\r\n1. Inject Cache like map reduce - maybe for forEach only?\r\n2. Component injection for ISPN components (needed for object filter) - seems any intermediate or terminal operation requires this?\r\n3. ~~Need to add serialization to a lot of classes (requires creating terminal operator classes)~~\r\n4. ~~Values stream isn't remote properly~~\r\n5. Investigate iterator parallel stream performance\r\n6. Add support for key filter applying to cache loader\r\n7. ~~Ensure short circuited operations terminate early (anyMatch, allMatch, noneMatch, findAny)~~\r\n8. Run rehash tests more (need to separate these into segment retrying, single run, iterator and forEach\r\n9. ~~tx context for non owned keys is broken (causes test failures)~~\r\n10. ~~Remote request uses OOB thread (requires new async changes - otherwise will need to listen to view changes in AbstractCacheBaseStream)~~ This is already fine.\r\n11. ~~Javadoc comments~~\r\n12. Segment completion listeners aren't implemented (also need tests)\r\n13. Add tests for skip & limit.\r\n14. Add tests for containsValue requiring serialization overhead.\r\n15. ~~Don't sort if collector doesn't support sorted items~~\r\n16. ~~Default batch size to be the same as state transfer size.~~\r\n17. Need to test a map/flatMap operation after an intermediate terminal operation such as sorted.  This is to verify the iterator doesn't use the different map operation.\r\n18. ~~Add if statements for tracing.~~ - This shouldn't be needed since logging framework does this internally.\r\n19. Add support for completing iterator early if it was closed.\r\n20. Add timeout for remote operations to be equal to replication sync timeout\r\n\r\n# General Design\r\n\r\nThis introduces support distributed Streams.  That is a backend implementation for the new Stream interface and its counterparts introduced with Java 8 when running in a distributed cache.\r\n\r\nEssentially all of the intermediate operations are stored until a terminal operation is invoked.  The intermediate operations and the terminal operation are then sent to each node in the cluster where it performs them for the data that node owns as primary.  Data is sent using the consistent hash and entries are limited by the provided segments.\r\n\r\nEach of these operations are also fully supported in a rehash aware manner.  There are 4 different types of terminal operators that have this processing\r\n\r\n1. SingleRunOperation - This operation only runs the terminal operation once and returns irrespective of any rehash occurrences.  This is useful for max, min, anyMatch, noneMatch etc. as we can safely run the entire operation on the provided segments.  Segments that were suspect are then sent back as the response and originator will resend it to the new owner   -https://github.com/infinispan/infinispan/pull/3569/files#diff-550f9268d848858a8722659ae03a9018\r\n2. SegmentRetryingTerminalOperation - This operation will run over and over until it knows it was ran during a stable topology.  This is useful for terminal operations that require exact segment completion for validity such as count, collect, average, reduce, sum etc.  Once a stable topology run is done any suspect segments are sent back in the response to the originator - https://github.com/infinispan/infinispan/pull/3569/files#diff-6386245ebb5d5ee61726619fa8b2d95a\r\n3. IteratorOperation - This operation has a few variants.  But essentially returns chunked data limited by distributedBatchSize number of keys.  The originator keeps track of keys retrieved by segment.  Once a segment is completed those keys are freed.  If a segment is found to be suspected from a node it will restart the process on the new owner sending the keys it had previously found as an exclusion list.  Primitive types are not optimized currently and will be auto boxed - https://github.com/infinispan/infinispan/pull/3569/files#diff-d75ad6cd39047d896c014174ce8ea9da\r\nhttps://issues.jboss.org/browse/ISPN-5293\r\n4. ForEachOperation - This operation also has a few variants.  It is similar to IteratorOperation in that it performs its operation controlled by distributedBatchSize of keys at a time.  Basically it collects  up to distributedBatchSize  and then performs the consumer and then sends a response to originator saying it performed the action on the given keys.  It will then retry just like IteratorOperation upon a rehash event.  Due to the nature of consumption being remote it is entirely possible that an action is ran more than once per key if a rehash occurs.  However this guarantees the operation is always done at least once. - https://github.com/infinispan/infinispan/pull/3569/files#diff-f3361efe09acfcef7dc3bdc4a8e71412\r\n\r\nThere are some special cases for intermediate operations as well.  This comes down to the sorted, distinct, limit and skip.  Basically these intermediate operations require local consolidation to perform properly.  Thus when these operations are invoked they will snapshot the intermediate operations and mark them as remote but any additional operations including this one will be performed locally by first doing an automatic iterator operation upon those remote operations.  Once the entries are retrieved using the iterator they will be applied to a local stream where all of the remaining intermediate operations are applied and the final terminal is invoked.\r\n\r\n1. Sorted - All entries are first drawn into memory on the originator before a final sort can be completed.  This will be enhanced with https://issues.jboss.org/browse/ISPN-4358.\r\n2. Distinct - This will add a remote distinct operation to limit entries returned as applicable.  Then all entries are returned and stored in memory until a final distinct can be applied.\r\n3. Limit - This will apply a remote limit operation so only so many entries are retrieved. Then all remaining entries will be streamed via iterator and once the number is found the iterator will be closed and no other entries will be returned.\r\n4. Skip - This will pull all entries via the iterator skipping the first retrieved values.","created_at":"2015-07-01T21:01:40Z","updated_at":"2015-07-28T13:56:31Z","closed_at":"2015-07-20T08:43:10Z","merged_at":null,"merge_commit_sha":"b10f12fe1adee22f9907fc7ac427cc5659646f54","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/infinispan/infinispan/pulls/3569/commits","review_comments_url":"https://api.github.com/repos/infinispan/infinispan/pulls/3569/comments","review_comment_url":"https://api.github.com/repos/infinispan/infinispan/pulls/comments{/number}","comments_url":"https://api.github.com/repos/infinispan/infinispan/issues/3569/comments","statuses_url":"https://api.github.com/repos/infinispan/infinispan/statuses/7c7b0639b93aa0f7ce1a0c21a28f6b065508c5f6","head":{"label":"wburns:ISPN-5293","ref":"ISPN-5293","sha":"7c7b0639b93aa0f7ce1a0c21a28f6b065508c5f6","user":{"login":"wburns","id":648175,"avatar_url":"https://avatars.githubusercontent.com/u/648175?v=3","gravatar_id":"","url":"https://api.github.com/users/wburns","html_url":"https://github.com/wburns","followers_url":"https://api.github.com/users/wburns/followers","following_url":"https://api.github.com/users/wburns/following{/other_user}","gists_url":"https://api.github.com/users/wburns/gists{/gist_id}","starred_url":"https://api.github.com/users/wburns/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wburns/subscriptions","organizations_url":"https://api.github.com/users/wburns/orgs","repos_url":"https://api.github.com/users/wburns/repos","events_url":"https://api.github.com/users/wburns/events{/privacy}","received_events_url":"https://api.github.com/users/wburns/received_events","type":"User","site_admin":false},"repo":{"id":2681545,"name":"infinispan","full_name":"wburns/infinispan","owner":{"login":"wburns","id":648175,"avatar_url":"https://avatars.githubusercontent.com/u/648175?v=3","gravatar_id":"","url":"https://api.github.com/users/wburns","html_url":"https://github.com/wburns","followers_url":"https://api.github.com/users/wburns/followers","following_url":"https://api.github.com/users/wburns/following{/other_user}","gists_url":"https://api.github.com/users/wburns/gists{/gist_id}","starred_url":"https://api.github.com/users/wburns/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wburns/subscriptions","organizations_url":"https://api.github.com/users/wburns/orgs","repos_url":"https://api.github.com/users/wburns/repos","events_url":"https://api.github.com/users/wburns/events{/privacy}","received_events_url":"https://api.github.com/users/wburns/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/wburns/infinispan","description":"Infinispan is an open source data grid platform and highly scalable NoSQL cloud data store.","fork":true,"url":"https://api.github.com/repos/wburns/infinispan","forks_url":"https://api.github.com/repos/wburns/infinispan/forks","keys_url":"https://api.github.com/repos/wburns/infinispan/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wburns/infinispan/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wburns/infinispan/teams","hooks_url":"https://api.github.com/repos/wburns/infinispan/hooks","issue_events_url":"https://api.github.com/repos/wburns/infinispan/issues/events{/number}","events_url":"https://api.github.com/repos/wburns/infinispan/events","assignees_url":"https://api.github.com/repos/wburns/infinispan/assignees{/user}","branches_url":"https://api.github.com/repos/wburns/infinispan/branches{/branch}","tags_url":"https://api.github.com/repos/wburns/infinispan/tags","blobs_url":"https://api.github.com/repos/wburns/infinispan/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wburns/infinispan/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wburns/infinispan/git/refs{/sha}","trees_url":"https://api.github.com/repos/wburns/infinispan/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wburns/infinispan/statuses/{sha}","languages_url":"https://api.github.com/repos/wburns/infinispan/languages","stargazers_url":"https://api.github.com/repos/wburns/infinispan/stargazers","contributors_url":"https://api.github.com/repos/wburns/infinispan/contributors","subscribers_url":"https://api.github.com/repos/wburns/infinispan/subscribers","subscription_url":"https://api.github.com/repos/wburns/infinispan/subscription","commits_url":"https://api.github.com/repos/wburns/infinispan/commits{/sha}","git_commits_url":"https://api.github.com/repos/wburns/infinispan/git/commits{/sha}","comments_url":"https://api.github.com/repos/wburns/infinispan/comments{/number}","issue_comment_url":"https://api.github.com/repos/wburns/infinispan/issues/comments{/number}","contents_url":"https://api.github.com/repos/wburns/infinispan/contents/{+path}","compare_url":"https://api.github.com/repos/wburns/infinispan/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wburns/infinispan/merges","archive_url":"https://api.github.com/repos/wburns/infinispan/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wburns/infinispan/downloads","issues_url":"https://api.github.com/repos/wburns/infinispan/issues{/number}","pulls_url":"https://api.github.com/repos/wburns/infinispan/pulls{/number}","milestones_url":"https://api.github.com/repos/wburns/infinispan/milestones{/number}","notifications_url":"https://api.github.com/repos/wburns/infinispan/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wburns/infinispan/labels{/name}","releases_url":"https://api.github.com/repos/wburns/infinispan/releases{/id}","created_at":"2011-10-31T15:31:04Z","updated_at":"2015-04-28T18:20:37Z","pushed_at":"2015-07-24T15:00:03Z","git_url":"git://github.com/wburns/infinispan.git","ssh_url":"git@github.com:wburns/infinispan.git","clone_url":"https://github.com/wburns/infinispan.git","svn_url":"https://github.com/wburns/infinispan","homepage":"http://www.infinispan.org","size":65673,"stargazers_count":1,"watchers_count":1,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"infinispan:master","ref":"master","sha":"c67c77122ff39d3d4dbda0e7e603ffcad72ce556","user":{"login":"infinispan","id":458093,"avatar_url":"https://avatars.githubusercontent.com/u/458093?v=3","gravatar_id":"","url":"https://api.github.com/users/infinispan","html_url":"https://github.com/infinispan","followers_url":"https://api.github.com/users/infinispan/followers","following_url":"https://api.github.com/users/infinispan/following{/other_user}","gists_url":"https://api.github.com/users/infinispan/gists{/gist_id}","starred_url":"https://api.github.com/users/infinispan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/infinispan/subscriptions","organizations_url":"https://api.github.com/users/infinispan/orgs","repos_url":"https://api.github.com/users/infinispan/repos","events_url":"https://api.github.com/users/infinispan/events{/privacy}","received_events_url":"https://api.github.com/users/infinispan/received_events","type":"Organization","site_admin":false},"repo":{"id":1050944,"name":"infinispan","full_name":"infinispan/infinispan","owner":{"login":"infinispan","id":458093,"avatar_url":"https://avatars.githubusercontent.com/u/458093?v=3","gravatar_id":"","url":"https://api.github.com/users/infinispan","html_url":"https://github.com/infinispan","followers_url":"https://api.github.com/users/infinispan/followers","following_url":"https://api.github.com/users/infinispan/following{/other_user}","gists_url":"https://api.github.com/users/infinispan/gists{/gist_id}","starred_url":"https://api.github.com/users/infinispan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/infinispan/subscriptions","organizations_url":"https://api.github.com/users/infinispan/orgs","repos_url":"https://api.github.com/users/infinispan/repos","events_url":"https://api.github.com/users/infinispan/events{/privacy}","received_events_url":"https://api.github.com/users/infinispan/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/infinispan/infinispan","description":"Infinispan is an open source data grid platform and highly scalable NoSQL cloud data store.","fork":false,"url":"https://api.github.com/repos/infinispan/infinispan","forks_url":"https://api.github.com/repos/infinispan/infinispan/forks","keys_url":"https://api.github.com/repos/infinispan/infinispan/keys{/key_id}","collaborators_url":"https://api.github.com/repos/infinispan/infinispan/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/infinispan/infinispan/teams","hooks_url":"https://api.github.com/repos/infinispan/infinispan/hooks","issue_events_url":"https://api.github.com/repos/infinispan/infinispan/issues/events{/number}","events_url":"https://api.github.com/repos/infinispan/infinispan/events","assignees_url":"https://api.github.com/repos/infinispan/infinispan/assignees{/user}","branches_url":"https://api.github.com/repos/infinispan/infinispan/branches{/branch}","tags_url":"https://api.github.com/repos/infinispan/infinispan/tags","blobs_url":"https://api.github.com/repos/infinispan/infinispan/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/infinispan/infinispan/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/infinispan/infinispan/git/refs{/sha}","trees_url":"https://api.github.com/repos/infinispan/infinispan/git/trees{/sha}","statuses_url":"https://api.github.com/repos/infinispan/infinispan/statuses/{sha}","languages_url":"https://api.github.com/repos/infinispan/infinispan/languages","stargazers_url":"https://api.github.com/repos/infinispan/infinispan/stargazers","contributors_url":"https://api.github.com/repos/infinispan/infinispan/contributors","subscribers_url":"https://api.github.com/repos/infinispan/infinispan/subscribers","subscription_url":"https://api.github.com/repos/infinispan/infinispan/subscription","commits_url":"https://api.github.com/repos/infinispan/infinispan/commits{/sha}","git_commits_url":"https://api.github.com/repos/infinispan/infinispan/git/commits{/sha}","comments_url":"https://api.github.com/repos/infinispan/infinispan/comments{/number}","issue_comment_url":"https://api.github.com/repos/infinispan/infinispan/issues/comments{/number}","contents_url":"https://api.github.com/repos/infinispan/infinispan/contents/{+path}","compare_url":"https://api.github.com/repos/infinispan/infinispan/compare/{base}...{head}","merges_url":"https://api.github.com/repos/infinispan/infinispan/merges","archive_url":"https://api.github.com/repos/infinispan/infinispan/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/infinispan/infinispan/downloads","issues_url":"https://api.github.com/repos/infinispan/infinispan/issues{/number}","pulls_url":"https://api.github.com/repos/infinispan/infinispan/pulls{/number}","milestones_url":"https://api.github.com/repos/infinispan/infinispan/milestones{/number}","notifications_url":"https://api.github.com/repos/infinispan/infinispan/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/infinispan/infinispan/labels{/name}","releases_url":"https://api.github.com/repos/infinispan/infinispan/releases{/id}","created_at":"2010-11-04T12:33:19Z","updated_at":"2015-07-27T04:13:48Z","pushed_at":"2015-07-28T13:41:20Z","git_url":"git://github.com/infinispan/infinispan.git","ssh_url":"git@github.com:infinispan/infinispan.git","clone_url":"https://github.com/infinispan/infinispan.git","svn_url":"https://github.com/infinispan/infinispan","homepage":"http://www.infinispan.org","size":155689,"stargazers_count":390,"watchers_count":390,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":296,"mirror_url":null,"open_issues_count":15,"forks":296,"open_issues":15,"watchers":390,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/infinispan/infinispan/pulls/3569"},"html":{"href":"https://github.com/infinispan/infinispan/pull/3569"},"issue":{"href":"https://api.github.com/repos/infinispan/infinispan/issues/3569"},"comments":{"href":"https://api.github.com/repos/infinispan/infinispan/issues/3569/comments"},"review_comments":{"href":"https://api.github.com/repos/infinispan/infinispan/pulls/3569/comments"},"review_comment":{"href":"https://api.github.com/repos/infinispan/infinispan/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/infinispan/infinispan/pulls/3569/commits"},"statuses":{"href":"https://api.github.com/repos/infinispan/infinispan/statuses/7c7b0639b93aa0f7ce1a0c21a28f6b065508c5f6"}}}}