Browse Source
* refactor zk client & zk config module * refactor zk client & zk config module * add licensepull/2/head
DK.Pino
5 years ago
committed by
qiaozhanwei
17 changed files with 923 additions and 320 deletions
@ -0,0 +1,288 @@ |
|||||||
|
/* |
||||||
|
* 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.dolphinscheduler.common.utils; |
||||||
|
|
||||||
|
import org.springframework.lang.Nullable; |
||||||
|
|
||||||
|
/** |
||||||
|
* A collection of static utility methods to validate input. |
||||||
|
* |
||||||
|
* <p>This class is modelled after Google Guava's Preconditions class, and partly takes code |
||||||
|
* from that class. We add this code to here base in order to reduce external |
||||||
|
* dependencies. |
||||||
|
*/ |
||||||
|
public final class Preconditions { |
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Null checks
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** |
||||||
|
* Ensures that the given object reference is not null. |
||||||
|
* Upon violation, a {@code NullPointerException} with no message is thrown. |
||||||
|
* |
||||||
|
* @param reference The object reference |
||||||
|
* @return The object reference itself (generically typed). |
||||||
|
* |
||||||
|
* @throws NullPointerException Thrown, if the passed reference was null. |
||||||
|
*/ |
||||||
|
public static <T> T checkNotNull(T reference) { |
||||||
|
if (reference == null) { |
||||||
|
throw new NullPointerException(); |
||||||
|
} |
||||||
|
return reference; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Ensures that the given object reference is not null. |
||||||
|
* Upon violation, a {@code NullPointerException} with the given message is thrown. |
||||||
|
* |
||||||
|
* @param reference The object reference |
||||||
|
* @param errorMessage The message for the {@code NullPointerException} that is thrown if the check fails. |
||||||
|
* @return The object reference itself (generically typed). |
||||||
|
* |
||||||
|
* @throws NullPointerException Thrown, if the passed reference was null. |
||||||
|
*/ |
||||||
|
public static <T> T checkNotNull(T reference, @Nullable String errorMessage) { |
||||||
|
if (reference == null) { |
||||||
|
throw new NullPointerException(String.valueOf(errorMessage)); |
||||||
|
} |
||||||
|
return reference; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Ensures that the given object reference is not null. |
||||||
|
* Upon violation, a {@code NullPointerException} with the given message is thrown. |
||||||
|
* |
||||||
|
* <p>The error message is constructed from a template and an arguments array, after |
||||||
|
* a similar fashion as {@link String#format(String, Object...)}, but supporting only |
||||||
|
* {@code %s} as a placeholder. |
||||||
|
* |
||||||
|
* @param reference The object reference |
||||||
|
* @param errorMessageTemplate The message template for the {@code NullPointerException} |
||||||
|
* that is thrown if the check fails. The template substitutes its |
||||||
|
* {@code %s} placeholders with the error message arguments. |
||||||
|
* @param errorMessageArgs The arguments for the error message, to be inserted into the |
||||||
|
* message template for the {@code %s} placeholders. |
||||||
|
* |
||||||
|
* @return The object reference itself (generically typed). |
||||||
|
* |
||||||
|
* @throws NullPointerException Thrown, if the passed reference was null. |
||||||
|
*/ |
||||||
|
public static <T> T checkNotNull(T reference, |
||||||
|
@Nullable String errorMessageTemplate, |
||||||
|
@Nullable Object... errorMessageArgs) { |
||||||
|
|
||||||
|
if (reference == null) { |
||||||
|
throw new NullPointerException(format(errorMessageTemplate, errorMessageArgs)); |
||||||
|
} |
||||||
|
return reference; |
||||||
|
} |
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Boolean Condition Checking (Argument)
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** |
||||||
|
* Checks the given boolean condition, and throws an {@code IllegalArgumentException} if |
||||||
|
* the condition is not met (evaluates to {@code false}). |
||||||
|
* |
||||||
|
* @param condition The condition to check |
||||||
|
* |
||||||
|
* @throws IllegalArgumentException Thrown, if the condition is violated. |
||||||
|
*/ |
||||||
|
public static void checkArgument(boolean condition) { |
||||||
|
if (!condition) { |
||||||
|
throw new IllegalArgumentException(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks the given boolean condition, and throws an {@code IllegalArgumentException} if |
||||||
|
* the condition is not met (evaluates to {@code false}). The exception will have the |
||||||
|
* given error message. |
||||||
|
* |
||||||
|
* @param condition The condition to check |
||||||
|
* @param errorMessage The message for the {@code IllegalArgumentException} that is thrown if the check fails. |
||||||
|
* |
||||||
|
* @throws IllegalArgumentException Thrown, if the condition is violated. |
||||||
|
*/ |
||||||
|
public static void checkArgument(boolean condition, @Nullable Object errorMessage) { |
||||||
|
if (!condition) { |
||||||
|
throw new IllegalArgumentException(String.valueOf(errorMessage)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks the given boolean condition, and throws an {@code IllegalArgumentException} if |
||||||
|
* the condition is not met (evaluates to {@code false}). |
||||||
|
* |
||||||
|
* @param condition The condition to check |
||||||
|
* @param errorMessageTemplate The message template for the {@code IllegalArgumentException} |
||||||
|
* that is thrown if the check fails. The template substitutes its |
||||||
|
* {@code %s} placeholders with the error message arguments. |
||||||
|
* @param errorMessageArgs The arguments for the error message, to be inserted into the |
||||||
|
* message template for the {@code %s} placeholders. |
||||||
|
* |
||||||
|
* @throws IllegalArgumentException Thrown, if the condition is violated. |
||||||
|
*/ |
||||||
|
public static void checkArgument(boolean condition, |
||||||
|
@Nullable String errorMessageTemplate, |
||||||
|
@Nullable Object... errorMessageArgs) { |
||||||
|
|
||||||
|
if (!condition) { |
||||||
|
throw new IllegalArgumentException(format(errorMessageTemplate, errorMessageArgs)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Boolean Condition Checking (State)
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** |
||||||
|
* Checks the given boolean condition, and throws an {@code IllegalStateException} if |
||||||
|
* the condition is not met (evaluates to {@code false}). |
||||||
|
* |
||||||
|
* @param condition The condition to check |
||||||
|
* |
||||||
|
* @throws IllegalStateException Thrown, if the condition is violated. |
||||||
|
*/ |
||||||
|
public static void checkState(boolean condition) { |
||||||
|
if (!condition) { |
||||||
|
throw new IllegalStateException(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks the given boolean condition, and throws an {@code IllegalStateException} if |
||||||
|
* the condition is not met (evaluates to {@code false}). The exception will have the |
||||||
|
* given error message. |
||||||
|
* |
||||||
|
* @param condition The condition to check |
||||||
|
* @param errorMessage The message for the {@code IllegalStateException} that is thrown if the check fails. |
||||||
|
* |
||||||
|
* @throws IllegalStateException Thrown, if the condition is violated. |
||||||
|
*/ |
||||||
|
public static void checkState(boolean condition, @Nullable Object errorMessage) { |
||||||
|
if (!condition) { |
||||||
|
throw new IllegalStateException(String.valueOf(errorMessage)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks the given boolean condition, and throws an {@code IllegalStateException} if |
||||||
|
* the condition is not met (evaluates to {@code false}). |
||||||
|
* |
||||||
|
* @param condition The condition to check |
||||||
|
* @param errorMessageTemplate The message template for the {@code IllegalStateException} |
||||||
|
* that is thrown if the check fails. The template substitutes its |
||||||
|
* {@code %s} placeholders with the error message arguments. |
||||||
|
* @param errorMessageArgs The arguments for the error message, to be inserted into the |
||||||
|
* message template for the {@code %s} placeholders. |
||||||
|
* |
||||||
|
* @throws IllegalStateException Thrown, if the condition is violated. |
||||||
|
*/ |
||||||
|
public static void checkState(boolean condition, |
||||||
|
@Nullable String errorMessageTemplate, |
||||||
|
@Nullable Object... errorMessageArgs) { |
||||||
|
|
||||||
|
if (!condition) { |
||||||
|
throw new IllegalStateException(format(errorMessageTemplate, errorMessageArgs)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Ensures that the given index is valid for an array, list or string of the given size. |
||||||
|
* |
||||||
|
* @param index index to check |
||||||
|
* @param size size of the array, list or string |
||||||
|
* |
||||||
|
* @throws IllegalArgumentException Thrown, if size is negative. |
||||||
|
* @throws IndexOutOfBoundsException Thrown, if the index negative or greater than or equal to size |
||||||
|
*/ |
||||||
|
public static void checkElementIndex(int index, int size) { |
||||||
|
checkArgument(size >= 0, "Size was negative."); |
||||||
|
if (index < 0 || index >= size) { |
||||||
|
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Ensures that the given index is valid for an array, list or string of the given size. |
||||||
|
* |
||||||
|
* @param index index to check |
||||||
|
* @param size size of the array, list or string |
||||||
|
* @param errorMessage The message for the {@code IndexOutOfBoundsException} that is thrown if the check fails. |
||||||
|
* |
||||||
|
* @throws IllegalArgumentException Thrown, if size is negative. |
||||||
|
* @throws IndexOutOfBoundsException Thrown, if the index negative or greater than or equal to size |
||||||
|
*/ |
||||||
|
public static void checkElementIndex(int index, int size, @Nullable String errorMessage) { |
||||||
|
checkArgument(size >= 0, "Size was negative."); |
||||||
|
if (index < 0 || index >= size) { |
||||||
|
throw new IndexOutOfBoundsException(String.valueOf(errorMessage) + " Index: " + index + ", Size: " + size); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Utilities
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** |
||||||
|
* A simplified formatting method. Similar to {@link String#format(String, Object...)}, but |
||||||
|
* with lower overhead (only String parameters, no locale, no format validation). |
||||||
|
* |
||||||
|
* <p>This method is taken quasi verbatim from the Guava Preconditions class. |
||||||
|
*/ |
||||||
|
private static String format(@Nullable String template, @Nullable Object... args) { |
||||||
|
final int numArgs = args == null ? 0 : args.length; |
||||||
|
template = String.valueOf(template); // null -> "null"
|
||||||
|
|
||||||
|
// start substituting the arguments into the '%s' placeholders
|
||||||
|
StringBuilder builder = new StringBuilder(template.length() + 16 * numArgs); |
||||||
|
int templateStart = 0; |
||||||
|
int i = 0; |
||||||
|
while (i < numArgs) { |
||||||
|
int placeholderStart = template.indexOf("%s", templateStart); |
||||||
|
if (placeholderStart == -1) { |
||||||
|
break; |
||||||
|
} |
||||||
|
builder.append(template.substring(templateStart, placeholderStart)); |
||||||
|
builder.append(args[i++]); |
||||||
|
templateStart = placeholderStart + 2; |
||||||
|
} |
||||||
|
builder.append(template.substring(templateStart)); |
||||||
|
|
||||||
|
// if we run out of placeholders, append the extra args in square braces
|
||||||
|
if (i < numArgs) { |
||||||
|
builder.append(" ["); |
||||||
|
builder.append(args[i++]); |
||||||
|
while (i < numArgs) { |
||||||
|
builder.append(", "); |
||||||
|
builder.append(args[i++]); |
||||||
|
} |
||||||
|
builder.append(']'); |
||||||
|
} |
||||||
|
|
||||||
|
return builder.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Private constructor to prevent instantiation. */ |
||||||
|
private Preconditions() {} |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
/* |
||||||
|
* 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.dolphinscheduler.common.zk; |
||||||
|
|
||||||
|
import org.apache.curator.framework.CuratorFramework; |
||||||
|
import org.apache.curator.framework.recipes.cache.TreeCacheEvent; |
||||||
|
import org.apache.curator.framework.recipes.cache.TreeCacheListener; |
||||||
|
|
||||||
|
public abstract class AbstractListener implements TreeCacheListener { |
||||||
|
|
||||||
|
@Override |
||||||
|
public final void childEvent(final CuratorFramework client, final TreeCacheEvent event) throws Exception { |
||||||
|
String path = null == event.getData() ? "" : event.getData().getPath(); |
||||||
|
if (path.isEmpty()) { |
||||||
|
return; |
||||||
|
} |
||||||
|
dataChanged(client, event, path); |
||||||
|
} |
||||||
|
|
||||||
|
protected abstract void dataChanged(final CuratorFramework client, final TreeCacheEvent event, final String path); |
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
/* |
||||||
|
* 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.dolphinscheduler.common.zk; |
||||||
|
|
||||||
|
import org.apache.curator.ensemble.EnsembleProvider; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
/** |
||||||
|
* default conf provider |
||||||
|
*/ |
||||||
|
public class DefaultEnsembleProvider implements EnsembleProvider { |
||||||
|
|
||||||
|
private final String serverList; |
||||||
|
|
||||||
|
public DefaultEnsembleProvider(String serverList){ |
||||||
|
this.serverList = serverList; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void start() throws Exception { |
||||||
|
//NOP
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getConnectionString() { |
||||||
|
return serverList; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void close() throws IOException { |
||||||
|
//NOP
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,82 @@ |
|||||||
|
/* |
||||||
|
* 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.dolphinscheduler.common.zk; |
||||||
|
|
||||||
|
import org.apache.curator.framework.recipes.cache.ChildData; |
||||||
|
import org.apache.curator.framework.recipes.cache.TreeCache; |
||||||
|
import org.apache.curator.framework.recipes.cache.TreeCacheListener; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
|
||||||
|
import static org.apache.dolphinscheduler.common.utils.Preconditions.*; |
||||||
|
import static org.apache.dolphinscheduler.common.utils.Preconditions.checkNotNull; |
||||||
|
|
||||||
|
@Component |
||||||
|
public class ZookeeperCachedOperator extends ZookeeperOperator { |
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(ZookeeperCachedOperator.class); |
||||||
|
|
||||||
|
//kay is zk path, value is TreeCache
|
||||||
|
private ConcurrentHashMap<String, TreeCache> allCaches = new ConcurrentHashMap<>(); |
||||||
|
|
||||||
|
/** |
||||||
|
* @param cachePath zk path |
||||||
|
* @param listener operator |
||||||
|
*/ |
||||||
|
public void registerListener(final String cachePath, final TreeCacheListener listener) { |
||||||
|
TreeCache newCache = new TreeCache(zkClient, cachePath); |
||||||
|
logger.info("add listener to zk path: {}", cachePath); |
||||||
|
try { |
||||||
|
newCache.start(); |
||||||
|
} catch (Exception e) { |
||||||
|
logger.error("add listener to zk path: {} failed", cachePath); |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
|
||||||
|
newCache.getListenable().addListener(listener); |
||||||
|
|
||||||
|
allCaches.put(cachePath, newCache); |
||||||
|
} |
||||||
|
|
||||||
|
public String getFromCache(final String cachePath, final String key) { |
||||||
|
ChildData resultInCache = allCaches.get(checkNotNull(cachePath)).getCurrentData(key); |
||||||
|
if (null != resultInCache) { |
||||||
|
return null == resultInCache.getData() ? null : new String(resultInCache.getData(), StandardCharsets.UTF_8); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public TreeCache getTreeCache(final String cachePath) { |
||||||
|
return allCaches.get(checkNotNull(cachePath)); |
||||||
|
} |
||||||
|
|
||||||
|
public void close() { |
||||||
|
|
||||||
|
allCaches.forEach((path, cache) -> { |
||||||
|
cache.close(); |
||||||
|
try { |
||||||
|
Thread.sleep(500); |
||||||
|
} catch (InterruptedException ignore) { |
||||||
|
} |
||||||
|
}); |
||||||
|
super.close(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,71 @@ |
|||||||
|
/* |
||||||
|
* 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.dolphinscheduler.common.zk; |
||||||
|
|
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
import org.apache.commons.configuration.Configuration; |
||||||
|
import org.springframework.beans.factory.annotation.Value; |
||||||
|
import org.springframework.context.annotation.PropertySource; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
|
||||||
|
/** |
||||||
|
* zookeeper conf |
||||||
|
*/ |
||||||
|
@Component |
||||||
|
@Data |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
@Builder |
||||||
|
@PropertySource("classpath:zookeeper.properties") |
||||||
|
public class ZookeeperConfig { |
||||||
|
|
||||||
|
//zk connect config
|
||||||
|
@Value("${zookeeper.quorum}") |
||||||
|
private String serverList; |
||||||
|
|
||||||
|
@Value("${zookeeper.retry.base.sleep:100}") |
||||||
|
private int baseSleepTimeMs; |
||||||
|
|
||||||
|
@Value("${zookeeper.retry.max.sleep:30000}") |
||||||
|
private int maxSleepMs; |
||||||
|
|
||||||
|
@Value("${zookeeper.retry.maxtime:10}") |
||||||
|
private int maxRetries; |
||||||
|
|
||||||
|
@Value("${zookeeper.session.timeout:60000}") |
||||||
|
private int sessionTimeoutMs; |
||||||
|
|
||||||
|
@Value("${zookeeper.connection.timeout:30000}") |
||||||
|
private int connectionTimeoutMs; |
||||||
|
|
||||||
|
@Value("${zookeeper.connection.digest: }") |
||||||
|
private String digest; |
||||||
|
|
||||||
|
//ds scheduler install config
|
||||||
|
@Value("${zookeeper.dolphinscheduler.root:/dolphinscheduler}") |
||||||
|
private String dsRoot; |
||||||
|
|
||||||
|
public static ZookeeperConfig getFromConf(Configuration conf){ |
||||||
|
return ZookeeperConfig.builder().serverList(conf.getString("zookeeper.quorum")).baseSleepTimeMs(conf.getInt("zookeeper.retry.base.sleep")) |
||||||
|
.maxSleepMs(conf.getInt("zookeeper.retry.max.sleep")).maxRetries(conf.getInt("zookeeper.retry.maxtime")) |
||||||
|
.sessionTimeoutMs(conf.getInt("zookeeper.session.timeout")).connectionTimeoutMs(conf.getInt("zookeeper.connection.timeout")) |
||||||
|
.dsRoot(conf.getString("zookeeper.dolphinscheduler.root")).build(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,232 @@ |
|||||||
|
/* |
||||||
|
* 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.dolphinscheduler.common.zk; |
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils; |
||||||
|
import org.apache.curator.framework.CuratorFramework; |
||||||
|
import org.apache.curator.framework.CuratorFrameworkFactory; |
||||||
|
import org.apache.curator.framework.api.ACLProvider; |
||||||
|
import org.apache.curator.framework.state.ConnectionState; |
||||||
|
import org.apache.curator.retry.ExponentialBackoffRetry; |
||||||
|
import org.apache.curator.utils.CloseableUtils; |
||||||
|
import org.apache.zookeeper.CreateMode; |
||||||
|
import org.apache.zookeeper.KeeperException; |
||||||
|
import org.apache.zookeeper.ZooDefs; |
||||||
|
import org.apache.zookeeper.data.ACL; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.springframework.beans.factory.InitializingBean; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
import org.springframework.util.CollectionUtils; |
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import static org.apache.dolphinscheduler.common.utils.Preconditions.*; |
||||||
|
import static org.apache.dolphinscheduler.common.utils.Preconditions.checkNotNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* zk base operator |
||||||
|
*/ |
||||||
|
@Component |
||||||
|
public class ZookeeperOperator implements InitializingBean { |
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(ZookeeperOperator.class); |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ZookeeperConfig zookeeperConfig; |
||||||
|
|
||||||
|
protected CuratorFramework zkClient; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void afterPropertiesSet() throws Exception { |
||||||
|
this.zkClient = buildClient(); |
||||||
|
initStateLister(); |
||||||
|
//init();
|
||||||
|
} |
||||||
|
|
||||||
|
//for subclass
|
||||||
|
//protected void init(){}
|
||||||
|
|
||||||
|
public void initStateLister() { |
||||||
|
checkNotNull(zkClient); |
||||||
|
|
||||||
|
zkClient.getConnectionStateListenable().addListener((client, newState) -> { |
||||||
|
if(newState == ConnectionState.LOST){ |
||||||
|
logger.error("connection lost from zookeeper"); |
||||||
|
} else if(newState == ConnectionState.RECONNECTED){ |
||||||
|
logger.info("reconnected to zookeeper"); |
||||||
|
} else if(newState == ConnectionState.SUSPENDED){ |
||||||
|
logger.warn("connection SUSPENDED to zookeeper"); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
private CuratorFramework buildClient() { |
||||||
|
logger.info("zookeeper registry center init, server lists is: {}.", zookeeperConfig.getServerList()); |
||||||
|
|
||||||
|
CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder().ensembleProvider(new DefaultEnsembleProvider(checkNotNull(zookeeperConfig.getServerList(),"zookeeper quorum can't be null"))) |
||||||
|
.retryPolicy(new ExponentialBackoffRetry(zookeeperConfig.getBaseSleepTimeMs(), zookeeperConfig.getMaxRetries(), zookeeperConfig.getMaxSleepMs())); |
||||||
|
|
||||||
|
//these has default value
|
||||||
|
if (0 != zookeeperConfig.getSessionTimeoutMs()) { |
||||||
|
builder.sessionTimeoutMs(zookeeperConfig.getSessionTimeoutMs()); |
||||||
|
} |
||||||
|
if (0 != zookeeperConfig.getConnectionTimeoutMs()) { |
||||||
|
builder.connectionTimeoutMs(zookeeperConfig.getConnectionTimeoutMs()); |
||||||
|
} |
||||||
|
if (StringUtils.isNotBlank(zookeeperConfig.getDigest())) { |
||||||
|
builder.authorization("digest", zookeeperConfig.getDigest().getBytes(StandardCharsets.UTF_8)).aclProvider(new ACLProvider() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<ACL> getDefaultAcl() { |
||||||
|
return ZooDefs.Ids.CREATOR_ALL_ACL; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<ACL> getAclForPath(final String path) { |
||||||
|
return ZooDefs.Ids.CREATOR_ALL_ACL; |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
zkClient = builder.build(); |
||||||
|
zkClient.start(); |
||||||
|
try { |
||||||
|
zkClient.blockUntilConnected(); |
||||||
|
} catch (final Exception ex) { |
||||||
|
throw new RuntimeException(ex); |
||||||
|
} |
||||||
|
return zkClient; |
||||||
|
} |
||||||
|
|
||||||
|
public String get(final String key) { |
||||||
|
try { |
||||||
|
return new String(zkClient.getData().forPath(key), StandardCharsets.UTF_8); |
||||||
|
} catch (Exception ex) { |
||||||
|
logger.error("get key : {}", key, ex); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public List<String> getChildrenKeys(final String key) { |
||||||
|
List<String> values; |
||||||
|
try { |
||||||
|
values = zkClient.getChildren().forPath(key); |
||||||
|
if (CollectionUtils.isEmpty(values)) { |
||||||
|
logger.warn("getChildrenKeys key : {} is empty", key); |
||||||
|
} |
||||||
|
return values; |
||||||
|
} catch (InterruptedException ex) { |
||||||
|
logger.error("getChildrenKeys key : {} InterruptedException", key); |
||||||
|
throw new IllegalStateException(ex); |
||||||
|
} catch (Exception ex) { |
||||||
|
logger.error("getChildrenKeys key : {}", key, ex); |
||||||
|
throw new RuntimeException(ex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isExisted(final String key) { |
||||||
|
try { |
||||||
|
return zkClient.checkExists().forPath(key) != null; |
||||||
|
} catch (Exception ex) { |
||||||
|
logger.error("isExisted key : {}", key, ex); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public void persist(final String key, final String value) { |
||||||
|
try { |
||||||
|
if (!isExisted(key)) { |
||||||
|
zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(key, value.getBytes(StandardCharsets.UTF_8)); |
||||||
|
} else { |
||||||
|
update(key, value); |
||||||
|
} |
||||||
|
} catch (Exception ex) { |
||||||
|
logger.error("persist key : {} , value : {}", key, value, ex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void update(final String key, final String value) { |
||||||
|
try { |
||||||
|
zkClient.inTransaction().check().forPath(key).and().setData().forPath(key, value.getBytes(StandardCharsets.UTF_8)).and().commit(); |
||||||
|
} catch (Exception ex) { |
||||||
|
logger.error("update key : {} , value : {}", key, value, ex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void persistEphemeral(final String key, final String value) { |
||||||
|
try { |
||||||
|
if (isExisted(key)) { |
||||||
|
try { |
||||||
|
zkClient.delete().deletingChildrenIfNeeded().forPath(key); |
||||||
|
} catch (KeeperException.NoNodeException ignore) { |
||||||
|
//NOP
|
||||||
|
} |
||||||
|
} |
||||||
|
zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(key, value.getBytes(StandardCharsets.UTF_8)); |
||||||
|
} catch (final Exception ex) { |
||||||
|
logger.error("persistEphemeral key : {} , value : {}", key, value, ex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void persistEphemeral(String key, String value, boolean overwrite) { |
||||||
|
try { |
||||||
|
if (overwrite) { |
||||||
|
persistEphemeral(key, value); |
||||||
|
} else { |
||||||
|
if (!isExisted(key)) { |
||||||
|
zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(key, value.getBytes(StandardCharsets.UTF_8)); |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (final Exception ex) { |
||||||
|
logger.error("persistEphemeral key : {} , value : {}, overwrite : {}", key, value, overwrite, ex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void persistEphemeralSequential(final String key, String value) { |
||||||
|
try { |
||||||
|
zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(key, value.getBytes(StandardCharsets.UTF_8)); |
||||||
|
} catch (final Exception ex) { |
||||||
|
logger.error("persistEphemeralSequential key : {}", key, ex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void remove(final String key) { |
||||||
|
try { |
||||||
|
if (isExisted(key)) { |
||||||
|
zkClient.delete().deletingChildrenIfNeeded().forPath(key); |
||||||
|
} |
||||||
|
} catch (KeeperException.NoNodeException ignore) { |
||||||
|
//NOP
|
||||||
|
} catch (final Exception ex) { |
||||||
|
logger.error("remove key : {}", key, ex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public CuratorFramework getZkClient() { |
||||||
|
return zkClient; |
||||||
|
} |
||||||
|
|
||||||
|
public ZookeeperConfig getZookeeperConfig() { |
||||||
|
return zookeeperConfig; |
||||||
|
} |
||||||
|
|
||||||
|
public void close() { |
||||||
|
CloseableUtils.closeQuietly(zkClient); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue