fabriziofortino commented on code in PR #922: URL: https://github.com/apache/jackrabbit-oak/pull/922#discussion_r1183791094
########## oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/RateLimitUtils.java: ########## @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.plugins.index; + +import java.lang.management.ManagementFactory; +import java.time.Duration; +import java.time.Instant; +import java.util.Calendar; +import java.util.Set; + +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; + +import org.apache.jackrabbit.util.ISO8601; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RateLimitUtils { + + private final static Logger LOG = LoggerFactory.getLogger(RateLimitUtils.class); + + // when getOldestAsyncIndexUpdate was called the last time + private static Instant lastJmxBeanCall = Instant.now(); Review Comment: this is never set again. Can it be marked as final? ########## oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/RateLimitUtils.java: ########## @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.plugins.index; + +import java.lang.management.ManagementFactory; +import java.time.Duration; +import java.time.Instant; +import java.util.Calendar; +import java.util.Set; + +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; + +import org.apache.jackrabbit.util.ISO8601; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RateLimitUtils { + + private final static Logger LOG = LoggerFactory.getLogger(RateLimitUtils.class); + + // when getOldestAsyncIndexUpdate was called the last time + private static Instant lastJmxBeanCall = Instant.now(); + + // the return value of the last call to getOldestAsyncIndexUpdate + private static Instant cachedOldestAsyncUpdate = Instant.now(); + + // the last time the rateLimitWrites was called + private static Instant lastRateLimitCall = Instant.now(); Review Comment: Should all these static vars be uppercased? ########## oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/RateLimitUtils.java: ########## @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.plugins.index; + +import java.lang.management.ManagementFactory; +import java.time.Duration; +import java.time.Instant; +import java.util.Calendar; +import java.util.Set; + +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; + +import org.apache.jackrabbit.util.ISO8601; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RateLimitUtils { + + private final static Logger LOG = LoggerFactory.getLogger(RateLimitUtils.class); + + // when getOldestAsyncIndexUpdate was called the last time + private static Instant lastJmxBeanCall = Instant.now(); + + // the return value of the last call to getOldestAsyncIndexUpdate + private static Instant cachedOldestAsyncUpdate = Instant.now(); + + // the last time the rateLimitWrites was called + private static Instant lastRateLimitCall = Instant.now(); + + private RateLimitUtils() { + } + + /** + * Rate limit writes in case indexes are lagging behind too far. The method + * returns immediately if all async indexes are up-to-date (updated in the last + * 30 seconds). + * + * If indexing lanes are lagging behind, however, the method will wait (using + * Thread.sleep) for at most 1 minute. If the method is called more than once + * per minute, it will sleep for at most the time that passed until the last + * call; that is, an application that is calling it a lot will be paused for up + * to 50%. This assumes indexes will be able to catch up in this situation. + * + * @return the number of milliseconds the call was sleeping + */ + public static long rateLimitWrites() { + Instant now = Instant.now(); + Duration delay = Duration.between(getOldestAsyncIndexUpdate(now), now); + return rateLimit(now, delay, true); + } + + static long rateLimit(Instant now, Duration delay, boolean callThreadSleep) { + long sleep; + if (delay.getSeconds() < 30) { + // less than 30 seconds: no need to wait + sleep = 0; + } else { + if (delay.toMinutes() > 60) { + LOG.warn("Indexing is delayed for {} minutes", delay.toMinutes()); + } + // sleep for as long as the duration between the last call and this call + sleep = Duration.between(lastRateLimitCall, now).toMillis(); + // sleep at most 1 minute + sleep = Math.min(sleep, Duration.ofMinutes(1).toMillis()); + // ensure we don't try to sleep negative values (it would throw IllegalArgumentException) + sleep = Math.max(0, sleep); + if (callThreadSleep) { + try { + Thread.sleep(sleep); + } catch (InterruptedException e) { + // ignore + } + } + now = now.plus(Duration.ofMillis(sleep)); + } + lastRateLimitCall = now; + return sleep; + } + + /** + * Get the timestamp of the oldest indexing lane. In the normal case, this is at + * most 5 seconds ago, if indexing lanes are updated every 5 seconds. If + * indexing is delayed, or paused, this can be in the past. + * + * The method can be called often without issues. If the last call was less than + * one second ago, the last returned value is returned. This is to avoid + * unnecessary calls to to the JMX beans. Review Comment: typo ```suggestion * unnecessary calls to the JMX beans. ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
