{"action":"created","comment":{"url":"https://api.github.com/repos/hazelcast/hazelcast/pulls/comments/219054838","pull_request_review_id":157131849,"id":219054838,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIxOTA1NDgzOA==","diff_hunk":"@@ -0,0 +1,681 @@\n+package com.hazelcast.internal.probing;\n+\n+import static com.hazelcast.internal.probing.CharSequenceUtils.appendEscaped;\n+import static com.hazelcast.internal.probing.CharSequenceUtils.appendUnescaped;\n+import static com.hazelcast.util.StringUtil.getterIntoProperty;\n+\n+import java.lang.reflect.Field;\n+import java.lang.reflect.Method;\n+import java.util.ArrayList;\n+import java.util.Arrays;\n+import java.util.Collection;\n+import java.util.Collections;\n+import java.util.Deque;\n+import java.util.HashSet;\n+import java.util.List;\n+import java.util.Map;\n+import java.util.Set;\n+import java.util.concurrent.ConcurrentHashMap;\n+import java.util.concurrent.ConcurrentLinkedDeque;\n+import java.util.concurrent.atomic.AtomicLong;\n+import java.util.function.Function;\n+\n+import com.hazelcast.internal.metrics.Probe;\n+import com.hazelcast.internal.metrics.ProbeLevel;\n+import com.hazelcast.internal.probing.ProbingCycle.Tagging;\n+import com.hazelcast.logging.ILogger;\n+import com.hazelcast.logging.Logger;\n+import com.hazelcast.util.Clock;\n+\n+public final class ProbeRegistryImpl implements ProbeRegistry {\n+\n+    private static final ILogger LOGGER = Logger.getLogger(ProbeRegistryImpl.class);\n+\n+    private static final Object[] EMPTY_ARGS = new Object[0];\n+\n+    private static final Map<Class<?>, ProbeAnnotatedType> PROBE_METADATA = \n+            new ConcurrentHashMap<Class<?>, ProbeAnnotatedType>();\n+\n+    private final Deque<ProbeSourceEntry> sources = new ConcurrentLinkedDeque<ProbeSourceEntry>();\n+\n+    @Override\n+    public void register(ProbeSource source) {\n+        for (ProbeSourceEntry e : sources) {\n+            if (e.source.equals(source)) {\n+                LOGGER.info(\"Probe source tried to register more then once: \"\n+                        + source.getClass().getSimpleName());\n+                return; // avoid adding the very same instance more then once\n+            }\n+        }\n+        sources.add(new ProbeSourceEntry(source));\n+    }\n+\n+    @Override\n+    public void registerIfSource(Object source) {\n+        if (source instanceof ProbeSource) {\n+            register((ProbeSource) source);\n+        }\n+    }\n+\n+    @Override\n+    public ProbeRenderContext newRenderingContext() {\n+        return new ProbingCycleImpl(sources);\n+    }\n+\n+    @Override\n+    public ProbeRenderContext newRenderingContext(Class<? extends ProbeSource>... filter) {\n+        Set<ProbeSourceEntry> filtered = new HashSet<ProbeSourceEntry>();\n+        for (ProbeSourceEntry e : sources) {\n+            for (Class<?> accepted : filter) {\n+                if (accepted == e.source.getClass()) {\n+                    filtered.add(e);\n+                }\n+            }\n+        }\n+        return new ProbingCycleImpl(filtered);\n+    }\n+\n+    /**\n+     * Wrapper for a {@link ProbeSource} for the state to keep track of it potential\n+     * need to be updated before being probed.\n+     */\n+    private static final class ProbeSourceEntry {\n+\n+        final ProbeSource source;\n+        final Method update;\n+        final long updateIntervalMs;\n+        final AtomicLong nextUpdateTimeMs = new AtomicLong();\n+        final ProbeLevel updateLevel;\n+\n+        public ProbeSourceEntry(ProbeSource source) {\n+            this.source = source;\n+            this.update = reprobeFor(source.getClass());\n+            if (update != null) {\n+                ReprobeCycle reprobe = update.getAnnotation(ReprobeCycle.class);\n+                updateIntervalMs = Probing.updateInterval(reprobe.value(), reprobe.unit());\n+                updateLevel = reprobe.level();\n+            } else {\n+                updateIntervalMs = -1L;\n+                updateLevel = ProbeLevel.DEBUG;\n+            }\n+        }\n+\n+        void updateIfNeeded() {\n+            if (update != null) {\n+                long next = nextUpdateTimeMs.get();\n+                long now = Clock.currentTimeMillis();\n+                if (now > next && nextUpdateTimeMs.compareAndSet(next, now + updateIntervalMs)) {\n+                    try {\n+                        update.invoke(source, EMPTY_ARGS);\n+                    } catch (Exception e) {\n+                        LOGGER.warning(\"Failed to update source: \"\n+                                + update.getDeclaringClass().getSimpleName() + \".\"\n+                                + update.getName(), e);\n+                    }\n+                }\n+            }\n+        }\n+\n+        static Method reprobeFor(Class<?> type) {\n+            for (Method m : type.getDeclaredMethods()) {\n+                if (m.isAnnotationPresent(ReprobeCycle.class)) {\n+                    m.setAccessible(true);\n+                    return m;\n+                }\n+            }\n+            return null;\n+        }\n+    }\n+\n+    private static final class ProbingCycleImpl\n+    implements ProbingCycle, ProbingCycle.Tags, ProbeRenderContext {\n+\n+        private final StringBuilder tags = new StringBuilder(128);\n+        private final Collection<ProbeSourceEntry> sources;\n+        private CharSequence lastTagName;\n+        private int lastTagValuePosition;\n+\n+        // render cycle state\n+        private ProbeRenderer renderer;\n+        private ProbeLevel level;\n+\n+        ProbingCycleImpl(Collection<ProbeSourceEntry> sources) {\n+            this.sources = sources;\n+        }\n+\n+        @Override\n+        public void renderAt(ProbeLevel level, ProbeRenderer renderer) {\n+            this.level = level;\n+            this.renderer = renderer;\n+            openContext(); // reset\n+            for (ProbeSourceEntry entry : sources) {\n+                if (isProbed(entry.updateLevel)) {\n+                    entry.updateIfNeeded();\n+                }\n+                try {\n+                    openContext(); // just to be sure it is done even if ommitted in the source\n+                    entry.source.probeIn(this);\n+                } catch (Exception e) {\n+                    LOGGER.warning(\"Exception while probing source \"\n+                            + entry.source.getClass().getSimpleName(), e);\n+                }\n+            }\n+        }\n+\n+        @Override\n+        public void probe(final ProbeLevel level, Object instance, final String... methods) {\n+            if (instance == null || !isProbed(level)) {\n+                return;\n+            }\n+            PROBE_METADATA.computeIfAbsent(instance.getClass(), new Function<Class<?>, ProbeAnnotatedType>() {\n+\n+                @Override\n+                public ProbeAnnotatedType apply(Class<?> type) {\n+                    return new ProbeAnnotatedType(type, level, methods);\n+                }\n+            }).probeIn(this, this.level, null, instance);\n+        }\n+\n+        @Override\n+        public void probe(Object instance) {\n+            probe(null, instance);\n+        }\n+\n+        @Override\n+        public void probe(CharSequence prefix, Object instance) {\n+            if (instance == null) {\n+                return;\n+            }\n+            PROBE_METADATA.computeIfAbsent(instance.getClass(), \n+                    new Function<Class<?>, ProbeAnnotatedType>() {\n+\n+                @Override\n+                public ProbeAnnotatedType apply(Class<?> type) {\n+                    //TODO use EMPTY constant or null for types that do not have probes at all\n+                    return new ProbeAnnotatedType(type);\n+                }\n+            }).probeIn(this, level, prefix, instance);\n+        }\n+\n+        @Override\n+        public void probe(Object[] instances) {\n+            if (instances != null) {\n+                for (int i = 0; i < instances.length; i++) {\n+                    probe(instances[i]); \n+                }\n+            }\n+        }\n+\n+        @Override\n+        public void probe(CharSequence name, long value) {\n+            probe(ProbeLevel.MANDATORY, name, value);\n+        }\n+\n+        @Override\n+        public void probe(CharSequence name, double value) {\n+            probe(ProbeLevel.MANDATORY, name, value);\n+        }\n+\n+        @Override\n+        public void probe(CharSequence name, boolean value) {\n+            probe(ProbeLevel.MANDATORY, name, value);\n+        }\n+\n+        @Override\n+        public void probe(ProbeLevel level, CharSequence name, long value) {\n+            if (isProbed(level)) {\n+                render(name, value);\n+            }\n+        }\n+\n+        @Override\n+        public void probe(ProbeLevel level, CharSequence name, double value) {\n+            probe(level, name, Probing.toLong(value));","path":"hazelcast/src/main/java/com/hazelcast/internal/probing/ProbeRegistryImpl.java","position":233,"original_position":233,"commit_id":"8e043d703b56e8433f28be31a0d9c2f707c81ffd","original_commit_id":"8e043d703b56e8433f28be31a0d9c2f707c81ffd","user":{"login":"pveentjer","id":105243,"node_id":"MDQ6VXNlcjEwNTI0Mw==","avatar_url":"https://avatars2.githubusercontent.com/u/105243?v=4","gravatar_id":"","url":"https://api.github.com/users/pveentjer","html_url":"https://github.com/pveentjer","followers_url":"https://api.github.com/users/pveentjer/followers","following_url":"https://api.github.com/users/pveentjer/following{/other_user}","gists_url":"https://api.github.com/users/pveentjer/gists{/gist_id}","starred_url":"https://api.github.com/users/pveentjer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pveentjer/subscriptions","organizations_url":"https://api.github.com/users/pveentjer/orgs","repos_url":"https://api.github.com/users/pveentjer/repos","events_url":"https://api.github.com/users/pveentjer/events{/privacy}","received_events_url":"https://api.github.com/users/pveentjer/received_events","type":"User","site_admin":false},"body":"litter.","created_at":"2018-09-20T07:04:01Z","updated_at":"2018-09-20T07:04:01Z","html_url":"https://github.com/hazelcast/hazelcast/pull/13806#discussion_r219054838","pull_request_url":"https://api.github.com/repos/hazelcast/hazelcast/pulls/13806","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/hazelcast/hazelcast/pulls/comments/219054838"},"html":{"href":"https://github.com/hazelcast/hazelcast/pull/13806#discussion_r219054838"},"pull_request":{"href":"https://api.github.com/repos/hazelcast/hazelcast/pulls/13806"}}},"pull_request":{"url":"https://api.github.com/repos/hazelcast/hazelcast/pulls/13806","id":216690555,"node_id":"MDExOlB1bGxSZXF1ZXN0MjE2NjkwNTU1","html_url":"https://github.com/hazelcast/hazelcast/pull/13806","diff_url":"https://github.com/hazelcast/hazelcast/pull/13806.diff","patch_url":"https://github.com/hazelcast/hazelcast/pull/13806.patch","issue_url":"https://api.github.com/repos/hazelcast/hazelcast/issues/13806","number":13806,"state":"open","locked":false,"title":"[3.12] Flexible low impact metrics probing","user":{"login":"jbee","id":309438,"node_id":"MDQ6VXNlcjMwOTQzOA==","avatar_url":"https://avatars3.githubusercontent.com/u/309438?v=4","gravatar_id":"","url":"https://api.github.com/users/jbee","html_url":"https://github.com/jbee","followers_url":"https://api.github.com/users/jbee/followers","following_url":"https://api.github.com/users/jbee/following{/other_user}","gists_url":"https://api.github.com/users/jbee/gists{/gist_id}","starred_url":"https://api.github.com/users/jbee/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jbee/subscriptions","organizations_url":"https://api.github.com/users/jbee/orgs","repos_url":"https://api.github.com/users/jbee/repos","events_url":"https://api.github.com/users/jbee/events{/privacy}","received_events_url":"https://api.github.com/users/jbee/received_events","type":"User","site_admin":false},"body":"Main goal was to provide a low memory consumption, low garbage probing in IMDG that also addresses the needs for a more flexible, low cost (additions and maintenance) metrics system for MC.\r\n\r\nIn the center of the change we go from `MetricsRegistry` to `ProbeRegistry`.\r\n\r\n**Starting Situation** \r\nThe old model was centered around a list of \"known\" probes that were registered on initialization. Dynamically changing probes (in presence or number) had to be managed by adding and removing them in connection with suiting events.\r\n\r\nConsequences: \r\n1. the memory needed grew linear with the number of probes\r\n2. dynamic probes required dedicated code and discipline to keep list of probes in sync with reality\r\n3. creation of garbage objects during registration was less relevant as only occurring once\r\n4. adding dynamic probes was costly (time/money/complexity) \r\n5. probes were predictable and could be globally ordered or probed individually\r\n\r\nWith an expected increase in number of probes due to MC using them as its main data source the memory consumption and the costs raised concerns about the model and its performance.\r\n\r\n**Solution**\r\nThe new model is centered around a list of \"known\" probe **sources** that are registered on initialization. The number of sources is small and fixed. The actual probes are \"discovered\" during each rendering cycle by asking the known sources to \"publish\" their probes or probe data. The API is design so that rendering probe data can be done in a way that avoids creating intermediate objects that become garbage. \r\n\r\nConsequences:\r\n1. memory consumption is low and fixed\r\n2. dynamic probes do not require special treatment (no dedicated code or state management)\r\n3. avoiding the creation of garbage objects during probing is highly relevant as occurring regularly\r\n4. adding dynamic probes is as cheap as adding fixed ones\r\n5. probes are not predictable and can only be ordered within local groups but not probed individually\r\n\r\n**Main Sources of Garbage**\r\nProbing is mostly garbage free. Some garbage cannot be avoided:\r\n* Iterator objects when iterating collections or maps\r\n* Primitive wrappers when probing methods returning primitives via reflection\r\n\r\n**Semantic Changes**\r\n* Clients collect and render the client statistics using the `ProbeRegistry`. As a consequence the `ProbeLevel` will now be obeyed. The client statistics no longer consist of a fix map of metrics but are dynamic and contain all metrics collected on client.\r\n* The client statistics send as `String` to a member is now split into the individual metrics by the member (without creating additional garbage) instead of sending it to MC and have MC deal with the `String`. \r\n* `HealthMonitor` runs a reduced set of `ProbeSource`s in `ProbeLevel.MANDATORY` to collect roughly the data it is interested in. Required probes not already being `MANDATORY` where made `MANDATORY` for that purpose.\r\n* Probing at different `ProbeLevel`s is possible (level are now dynamic)\r\n* `LocalXyzStats` classes now cache whether or not statistics for the object was enabled\r\n* only objects with enabled statistics are probed\r\n\r\nTo be continued...","created_at":"2018-09-19T15:52:20Z","updated_at":"2018-09-20T07:04:01Z","closed_at":null,"merged_at":null,"merge_commit_sha":"db17e9265ca6ea93718e881c5ad19d0ce3d973cd","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":137752575,"node_id":"MDU6TGFiZWwxMzc3NTI1NzU=","url":"https://api.github.com/repos/hazelcast/hazelcast/labels/Team:%20Core","name":"Team: Core","color":"fef2c0","default":false},{"id":1740692,"node_id":"MDU6TGFiZWwxNzQwNjky","url":"https://api.github.com/repos/hazelcast/hazelcast/labels/Type:%20Enhancement","name":"Type: Enhancement","color":"5319e7","default":false}],"milestone":{"url":"https://api.github.com/repos/hazelcast/hazelcast/milestones/112","html_url":"https://github.com/hazelcast/hazelcast/milestone/112","labels_url":"https://api.github.com/repos/hazelcast/hazelcast/milestones/112/labels","id":3354840,"node_id":"MDk6TWlsZXN0b25lMzM1NDg0MA==","number":112,"title":"3.12","description":null,"creator":{"login":"burakcelebi","id":928875,"node_id":"MDQ6VXNlcjkyODg3NQ==","avatar_url":"https://avatars1.githubusercontent.com/u/928875?v=4","gravatar_id":"","url":"https://api.github.com/users/burakcelebi","html_url":"https://github.com/burakcelebi","followers_url":"https://api.github.com/users/burakcelebi/followers","following_url":"https://api.github.com/users/burakcelebi/following{/other_user}","gists_url":"https://api.github.com/users/burakcelebi/gists{/gist_id}","starred_url":"https://api.github.com/users/burakcelebi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/burakcelebi/subscriptions","organizations_url":"https://api.github.com/users/burakcelebi/orgs","repos_url":"https://api.github.com/users/burakcelebi/repos","events_url":"https://api.github.com/users/burakcelebi/events{/privacy}","received_events_url":"https://api.github.com/users/burakcelebi/received_events","type":"User","site_admin":false},"open_issues":237,"closed_issues":5,"state":"open","created_at":"2018-05-17T14:36:02Z","updated_at":"2018-09-19T15:58:01Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/hazelcast/hazelcast/pulls/13806/commits","review_comments_url":"https://api.github.com/repos/hazelcast/hazelcast/pulls/13806/comments","review_comment_url":"https://api.github.com/repos/hazelcast/hazelcast/pulls/comments{/number}","comments_url":"https://api.github.com/repos/hazelcast/hazelcast/issues/13806/comments","statuses_url":"https://api.github.com/repos/hazelcast/hazelcast/statuses/8e043d703b56e8433f28be31a0d9c2f707c81ffd","head":{"label":"jbee:sktech-probe-rendering","ref":"sktech-probe-rendering","sha":"8e043d703b56e8433f28be31a0d9c2f707c81ffd","user":{"login":"jbee","id":309438,"node_id":"MDQ6VXNlcjMwOTQzOA==","avatar_url":"https://avatars3.githubusercontent.com/u/309438?v=4","gravatar_id":"","url":"https://api.github.com/users/jbee","html_url":"https://github.com/jbee","followers_url":"https://api.github.com/users/jbee/followers","following_url":"https://api.github.com/users/jbee/following{/other_user}","gists_url":"https://api.github.com/users/jbee/gists{/gist_id}","starred_url":"https://api.github.com/users/jbee/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jbee/subscriptions","organizations_url":"https://api.github.com/users/jbee/orgs","repos_url":"https://api.github.com/users/jbee/repos","events_url":"https://api.github.com/users/jbee/events{/privacy}","received_events_url":"https://api.github.com/users/jbee/received_events","type":"User","site_admin":false},"repo":{"id":118611399,"node_id":"MDEwOlJlcG9zaXRvcnkxMTg2MTEzOTk=","name":"hazelcast","full_name":"jbee/hazelcast","private":false,"owner":{"login":"jbee","id":309438,"node_id":"MDQ6VXNlcjMwOTQzOA==","avatar_url":"https://avatars3.githubusercontent.com/u/309438?v=4","gravatar_id":"","url":"https://api.github.com/users/jbee","html_url":"https://github.com/jbee","followers_url":"https://api.github.com/users/jbee/followers","following_url":"https://api.github.com/users/jbee/following{/other_user}","gists_url":"https://api.github.com/users/jbee/gists{/gist_id}","starred_url":"https://api.github.com/users/jbee/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jbee/subscriptions","organizations_url":"https://api.github.com/users/jbee/orgs","repos_url":"https://api.github.com/users/jbee/repos","events_url":"https://api.github.com/users/jbee/events{/privacy}","received_events_url":"https://api.github.com/users/jbee/received_events","type":"User","site_admin":false},"html_url":"https://github.com/jbee/hazelcast","description":"Open Source In-Memory Data Grid","fork":true,"url":"https://api.github.com/repos/jbee/hazelcast","forks_url":"https://api.github.com/repos/jbee/hazelcast/forks","keys_url":"https://api.github.com/repos/jbee/hazelcast/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jbee/hazelcast/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jbee/hazelcast/teams","hooks_url":"https://api.github.com/repos/jbee/hazelcast/hooks","issue_events_url":"https://api.github.com/repos/jbee/hazelcast/issues/events{/number}","events_url":"https://api.github.com/repos/jbee/hazelcast/events","assignees_url":"https://api.github.com/repos/jbee/hazelcast/assignees{/user}","branches_url":"https://api.github.com/repos/jbee/hazelcast/branches{/branch}","tags_url":"https://api.github.com/repos/jbee/hazelcast/tags","blobs_url":"https://api.github.com/repos/jbee/hazelcast/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jbee/hazelcast/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jbee/hazelcast/git/refs{/sha}","trees_url":"https://api.github.com/repos/jbee/hazelcast/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jbee/hazelcast/statuses/{sha}","languages_url":"https://api.github.com/repos/jbee/hazelcast/languages","stargazers_url":"https://api.github.com/repos/jbee/hazelcast/stargazers","contributors_url":"https://api.github.com/repos/jbee/hazelcast/contributors","subscribers_url":"https://api.github.com/repos/jbee/hazelcast/subscribers","subscription_url":"https://api.github.com/repos/jbee/hazelcast/subscription","commits_url":"https://api.github.com/repos/jbee/hazelcast/commits{/sha}","git_commits_url":"https://api.github.com/repos/jbee/hazelcast/git/commits{/sha}","comments_url":"https://api.github.com/repos/jbee/hazelcast/comments{/number}","issue_comment_url":"https://api.github.com/repos/jbee/hazelcast/issues/comments{/number}","contents_url":"https://api.github.com/repos/jbee/hazelcast/contents/{+path}","compare_url":"https://api.github.com/repos/jbee/hazelcast/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jbee/hazelcast/merges","archive_url":"https://api.github.com/repos/jbee/hazelcast/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jbee/hazelcast/downloads","issues_url":"https://api.github.com/repos/jbee/hazelcast/issues{/number}","pulls_url":"https://api.github.com/repos/jbee/hazelcast/pulls{/number}","milestones_url":"https://api.github.com/repos/jbee/hazelcast/milestones{/number}","notifications_url":"https://api.github.com/repos/jbee/hazelcast/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jbee/hazelcast/labels{/name}","releases_url":"https://api.github.com/repos/jbee/hazelcast/releases{/id}","deployments_url":"https://api.github.com/repos/jbee/hazelcast/deployments","created_at":"2018-01-23T13:06:06Z","updated_at":"2018-09-19T15:17:56Z","pushed_at":"2018-09-19T15:27:01Z","git_url":"git://github.com/jbee/hazelcast.git","ssh_url":"git@github.com:jbee/hazelcast.git","clone_url":"https://github.com/jbee/hazelcast.git","svn_url":"https://github.com/jbee/hazelcast","homepage":"http://www.hazelcast.org","size":134823,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"hazelcast:master","ref":"master","sha":"20293d173f1f09e3f4a93fd292a8a288a2e676a9","user":{"login":"hazelcast","id":1453152,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE0NTMxNTI=","avatar_url":"https://avatars2.githubusercontent.com/u/1453152?v=4","gravatar_id":"","url":"https://api.github.com/users/hazelcast","html_url":"https://github.com/hazelcast","followers_url":"https://api.github.com/users/hazelcast/followers","following_url":"https://api.github.com/users/hazelcast/following{/other_user}","gists_url":"https://api.github.com/users/hazelcast/gists{/gist_id}","starred_url":"https://api.github.com/users/hazelcast/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hazelcast/subscriptions","organizations_url":"https://api.github.com/users/hazelcast/orgs","repos_url":"https://api.github.com/users/hazelcast/repos","events_url":"https://api.github.com/users/hazelcast/events{/privacy}","received_events_url":"https://api.github.com/users/hazelcast/received_events","type":"Organization","site_admin":false},"repo":{"id":3786237,"node_id":"MDEwOlJlcG9zaXRvcnkzNzg2MjM3","name":"hazelcast","full_name":"hazelcast/hazelcast","private":false,"owner":{"login":"hazelcast","id":1453152,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE0NTMxNTI=","avatar_url":"https://avatars2.githubusercontent.com/u/1453152?v=4","gravatar_id":"","url":"https://api.github.com/users/hazelcast","html_url":"https://github.com/hazelcast","followers_url":"https://api.github.com/users/hazelcast/followers","following_url":"https://api.github.com/users/hazelcast/following{/other_user}","gists_url":"https://api.github.com/users/hazelcast/gists{/gist_id}","starred_url":"https://api.github.com/users/hazelcast/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hazelcast/subscriptions","organizations_url":"https://api.github.com/users/hazelcast/orgs","repos_url":"https://api.github.com/users/hazelcast/repos","events_url":"https://api.github.com/users/hazelcast/events{/privacy}","received_events_url":"https://api.github.com/users/hazelcast/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/hazelcast/hazelcast","description":"Open Source In-Memory Data Grid","fork":false,"url":"https://api.github.com/repos/hazelcast/hazelcast","forks_url":"https://api.github.com/repos/hazelcast/hazelcast/forks","keys_url":"https://api.github.com/repos/hazelcast/hazelcast/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hazelcast/hazelcast/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hazelcast/hazelcast/teams","hooks_url":"https://api.github.com/repos/hazelcast/hazelcast/hooks","issue_events_url":"https://api.github.com/repos/hazelcast/hazelcast/issues/events{/number}","events_url":"https://api.github.com/repos/hazelcast/hazelcast/events","assignees_url":"https://api.github.com/repos/hazelcast/hazelcast/assignees{/user}","branches_url":"https://api.github.com/repos/hazelcast/hazelcast/branches{/branch}","tags_url":"https://api.github.com/repos/hazelcast/hazelcast/tags","blobs_url":"https://api.github.com/repos/hazelcast/hazelcast/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hazelcast/hazelcast/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hazelcast/hazelcast/git/refs{/sha}","trees_url":"https://api.github.com/repos/hazelcast/hazelcast/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hazelcast/hazelcast/statuses/{sha}","languages_url":"https://api.github.com/repos/hazelcast/hazelcast/languages","stargazers_url":"https://api.github.com/repos/hazelcast/hazelcast/stargazers","contributors_url":"https://api.github.com/repos/hazelcast/hazelcast/contributors","subscribers_url":"https://api.github.com/repos/hazelcast/hazelcast/subscribers","subscription_url":"https://api.github.com/repos/hazelcast/hazelcast/subscription","commits_url":"https://api.github.com/repos/hazelcast/hazelcast/commits{/sha}","git_commits_url":"https://api.github.com/repos/hazelcast/hazelcast/git/commits{/sha}","comments_url":"https://api.github.com/repos/hazelcast/hazelcast/comments{/number}","issue_comment_url":"https://api.github.com/repos/hazelcast/hazelcast/issues/comments{/number}","contents_url":"https://api.github.com/repos/hazelcast/hazelcast/contents/{+path}","compare_url":"https://api.github.com/repos/hazelcast/hazelcast/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hazelcast/hazelcast/merges","archive_url":"https://api.github.com/repos/hazelcast/hazelcast/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hazelcast/hazelcast/downloads","issues_url":"https://api.github.com/repos/hazelcast/hazelcast/issues{/number}","pulls_url":"https://api.github.com/repos/hazelcast/hazelcast/pulls{/number}","milestones_url":"https://api.github.com/repos/hazelcast/hazelcast/milestones{/number}","notifications_url":"https://api.github.com/repos/hazelcast/hazelcast/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hazelcast/hazelcast/labels{/name}","releases_url":"https://api.github.com/repos/hazelcast/hazelcast/releases{/id}","deployments_url":"https://api.github.com/repos/hazelcast/hazelcast/deployments","created_at":"2012-03-21T12:25:18Z","updated_at":"2018-09-20T06:59:11Z","pushed_at":"2018-09-20T06:58:58Z","git_url":"git://github.com/hazelcast/hazelcast.git","ssh_url":"git@github.com:hazelcast/hazelcast.git","clone_url":"https://github.com/hazelcast/hazelcast.git","svn_url":"https://github.com/hazelcast/hazelcast","homepage":"http://www.hazelcast.org","size":135075,"stargazers_count":2751,"watchers_count":2751,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1062,"mirror_url":null,"archived":false,"open_issues_count":673,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":1062,"open_issues":673,"watchers":2751,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/hazelcast/hazelcast/pulls/13806"},"html":{"href":"https://github.com/hazelcast/hazelcast/pull/13806"},"issue":{"href":"https://api.github.com/repos/hazelcast/hazelcast/issues/13806"},"comments":{"href":"https://api.github.com/repos/hazelcast/hazelcast/issues/13806/comments"},"review_comments":{"href":"https://api.github.com/repos/hazelcast/hazelcast/pulls/13806/comments"},"review_comment":{"href":"https://api.github.com/repos/hazelcast/hazelcast/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/hazelcast/hazelcast/pulls/13806/commits"},"statuses":{"href":"https://api.github.com/repos/hazelcast/hazelcast/statuses/8e043d703b56e8433f28be31a0d9c2f707c81ffd"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"pveentjer"}}