You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by sh...@apache.org on 2018/10/23 13:27:13 UTC
[kylin] branch master updated: KYLIN-3633 Avoid potential dead lock
when building global dictionary
This is an automated email from the ASF dual-hosted git repository.
shaofengshi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kylin.git
The following commit(s) were added to refs/heads/master by this push:
new 8b51d4a KYLIN-3633 Avoid potential dead lock when building global dictionary
8b51d4a is described below
commit 8b51d4a0cd8c33ded5bb380885a731c381da710d
Author: nichunen <ch...@kyligence.io>
AuthorDate: Tue Oct 23 20:46:58 2018 +0800
KYLIN-3633 Avoid potential dead lock when building global dictionary
---
.../org/apache/kylin/dict/DictionaryGenerator.java | 47 +++++++++++++--
.../apache/kylin/dict/GlobalDictionaryBuilder.java | 9 ++-
.../org/apache/kylin/dict/IDictionaryBuilder.java | 3 +
.../dict/global/SegmentAppendTrieDictBuilder.java | 5 ++
.../kylin/dict/ITGlobalDictionaryBuilderTest.java | 68 ++++++++++++++++++----
5 files changed, 114 insertions(+), 18 deletions(-)
diff --git a/core-dictionary/src/main/java/org/apache/kylin/dict/DictionaryGenerator.java b/core-dictionary/src/main/java/org/apache/kylin/dict/DictionaryGenerator.java
index db0c302..7c33b4a 100644
--- a/core-dictionary/src/main/java/org/apache/kylin/dict/DictionaryGenerator.java
+++ b/core-dictionary/src/main/java/org/apache/kylin/dict/DictionaryGenerator.java
@@ -75,13 +75,19 @@ public class DictionaryGenerator {
builder.init(dictInfo, baseId, null);
// add values
- while (valueEnumerator.moveNext()) {
- String value = valueEnumerator.current();
+ try {
+ while (valueEnumerator.moveNext()) {
+ String value = valueEnumerator.current();
- boolean accept = builder.addValue(value);
+ boolean accept = builder.addValue(value);
- if (accept && samples.size() < nSamples && samples.contains(value) == false)
- samples.add(value);
+ if (accept && samples.size() < nSamples && samples.contains(value) == false)
+ samples.add(value);
+ }
+ } catch (IOException e) {
+ logger.error("Error during adding dict value.", e);
+ builder.clear();
+ throw e;
}
// build
@@ -149,6 +155,12 @@ public class DictionaryGenerator {
return new DateStrDictionary(datePattern, baseId);
}
+
+
+ @Override
+ public void clear() {
+ // do nothing
+ }
}
private static class TimeDictBuilder implements IDictionaryBuilder {
@@ -171,6 +183,11 @@ public class DictionaryGenerator {
public Dictionary<String> build() throws IOException {
return new TimeStrDictionary(); // base ID is always 0
}
+
+ @Override
+ public void clear() {
+
+ }
}
private static class StringTrieDictBuilder implements IDictionaryBuilder {
@@ -196,6 +213,11 @@ public class DictionaryGenerator {
public Dictionary<String> build() throws IOException {
return builder.build(baseId);
}
+
+ @Override
+ public void clear() {
+
+ }
}
private static class StringTrieDictForestBuilder implements IDictionaryBuilder {
@@ -219,6 +241,11 @@ public class DictionaryGenerator {
public Dictionary<String> build() throws IOException {
return builder.build();
}
+
+ @Override
+ public void clear() {
+
+ }
}
@SuppressWarnings("deprecation")
@@ -245,6 +272,11 @@ public class DictionaryGenerator {
public Dictionary<String> build() throws IOException {
return builder.build(baseId);
}
+
+ @Override
+ public void clear() {
+
+ }
}
private static class NumberTrieDictForestBuilder implements IDictionaryBuilder {
@@ -268,6 +300,11 @@ public class DictionaryGenerator {
public Dictionary<String> build() throws IOException {
return builder.build();
}
+
+ @Override
+ public void clear() {
+
+ }
}
}
diff --git a/core-dictionary/src/main/java/org/apache/kylin/dict/GlobalDictionaryBuilder.java b/core-dictionary/src/main/java/org/apache/kylin/dict/GlobalDictionaryBuilder.java
index 9168ca4..d813793 100644
--- a/core-dictionary/src/main/java/org/apache/kylin/dict/GlobalDictionaryBuilder.java
+++ b/core-dictionary/src/main/java/org/apache/kylin/dict/GlobalDictionaryBuilder.java
@@ -19,8 +19,8 @@
package org.apache.kylin.dict;
import java.io.IOException;
-
import java.util.Locale;
+
import org.apache.kylin.common.KylinConfig;
import org.apache.kylin.common.lock.DistributedLock;
import org.apache.kylin.common.util.Dictionary;
@@ -104,6 +104,13 @@ public class GlobalDictionaryBuilder implements IDictionaryBuilder {
return new AppendTrieDictionary<>();
}
+ @Override
+ public void clear() {
+ if (lock.isLocked(getLockPath(sourceColumn))) {
+ lock.unlock(getLockPath(sourceColumn));
+ }
+ }
+
private String getLockPath(String pathName) {
return "/dict/" + pathName + "/lock";
}
diff --git a/core-dictionary/src/main/java/org/apache/kylin/dict/IDictionaryBuilder.java b/core-dictionary/src/main/java/org/apache/kylin/dict/IDictionaryBuilder.java
index e2a643d..771bfb4 100644
--- a/core-dictionary/src/main/java/org/apache/kylin/dict/IDictionaryBuilder.java
+++ b/core-dictionary/src/main/java/org/apache/kylin/dict/IDictionaryBuilder.java
@@ -35,4 +35,7 @@ public interface IDictionaryBuilder {
/** Build the dictionary */
Dictionary<String> build() throws IOException;
+
+ /** Clear before exit */
+ void clear();
}
diff --git a/core-dictionary/src/main/java/org/apache/kylin/dict/global/SegmentAppendTrieDictBuilder.java b/core-dictionary/src/main/java/org/apache/kylin/dict/global/SegmentAppendTrieDictBuilder.java
index f8640a0..770b0bc 100644
--- a/core-dictionary/src/main/java/org/apache/kylin/dict/global/SegmentAppendTrieDictBuilder.java
+++ b/core-dictionary/src/main/java/org/apache/kylin/dict/global/SegmentAppendTrieDictBuilder.java
@@ -78,4 +78,9 @@ public class SegmentAppendTrieDictBuilder implements IDictionaryBuilder {
public Dictionary<String> build() throws IOException {
return builder.build(baseId);
}
+
+ @Override
+ public void clear() {
+
+ }
}
diff --git a/kylin-it/src/test/java/org/apache/kylin/dict/ITGlobalDictionaryBuilderTest.java b/kylin-it/src/test/java/org/apache/kylin/dict/ITGlobalDictionaryBuilderTest.java
index c578a57..94c4f56 100644
--- a/kylin-it/src/test/java/org/apache/kylin/dict/ITGlobalDictionaryBuilderTest.java
+++ b/kylin-it/src/test/java/org/apache/kylin/dict/ITGlobalDictionaryBuilderTest.java
@@ -18,20 +18,21 @@
package org.apache.kylin.dict;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+
import org.apache.hadoop.fs.Path;
import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.common.lock.DistributedLock;
import org.apache.kylin.common.util.Dictionary;
import org.apache.kylin.common.util.HBaseMetadataTestCase;
import org.apache.kylin.common.util.HadoopUtil;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
-
-import java.io.IOException;
-import java.util.concurrent.CountDownLatch;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
+import org.junit.rules.ExpectedException;
public class ITGlobalDictionaryBuilderTest extends HBaseMetadataTestCase {
private DictionaryInfo dictionaryInfo;
@@ -48,8 +49,12 @@ public class ITGlobalDictionaryBuilderTest extends HBaseMetadataTestCase {
staticCleanupTestMetadata();
}
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
private void cleanup() {
- String BASE_DIR = KylinConfig.getInstanceFromEnv().getHdfsWorkingDirectory() + "/resources/GlobalDict" + dictionaryInfo.getResourceDir() + "/";
+ String BASE_DIR = KylinConfig.getInstanceFromEnv().getHdfsWorkingDirectory() + "/resources/GlobalDict"
+ + dictionaryInfo.getResourceDir() + "/";
Path basePath = new Path(BASE_DIR);
try {
HadoopUtil.getFileSystem(basePath).delete(basePath, true);
@@ -77,16 +82,33 @@ public class ITGlobalDictionaryBuilderTest extends HBaseMetadataTestCase {
Dictionary<String> dict = builder.build();
for (int i = 0; i < 10000; i++) {
- assertNotEquals(-1, dict.getIdFromValue("t1_" + i));
+ Assert.assertNotEquals(-1, dict.getIdFromValue("t1_" + i));
}
for (int i = 0; i < 10; i++) {
- assertNotEquals(-1, dict.getIdFromValue("t2_" + i));
+ Assert.assertNotEquals(-1, dict.getIdFromValue("t2_" + i));
}
for (int i = 0; i < 100000; i++) {
- assertNotEquals(-1, dict.getIdFromValue("t3_" + i));
+ Assert.assertNotEquals(-1, dict.getIdFromValue("t3_" + i));
}
- assertEquals(110011, dict.getIdFromValue("success"));
+ Assert.assertEquals(110011, dict.getIdFromValue("success"));
+ }
+
+ @Test
+ public void testBuildGlobalDictFailed() throws IOException {
+ thrown.expect(IOException.class);
+ thrown.expectMessage("read failed.");
+
+ GlobalDictionaryBuilder builder = new GlobalDictionaryBuilder();
+ try {
+ DictionaryGenerator.buildDictionary(builder, dictionaryInfo, new ErrorDictionaryValueEnumerator());
+ } catch (Throwable e) {
+ DistributedLock lock = KylinConfig.getInstanceFromEnv().getDistributedLockFactory().lockForCurrentThread();
+ String lockPath = "/dict/" + dictionaryInfo.getSourceTable() + "_" + dictionaryInfo.getSourceColumn()
+ + "/lock";
+ Assert.assertFalse(lock.isLocked(lockPath));
+ throw e;
+ }
}
private class SharedBuilderThread extends Thread {
@@ -118,4 +140,26 @@ public class ITGlobalDictionaryBuilderTest extends HBaseMetadataTestCase {
}
}
}
-}
+
+ private class ErrorDictionaryValueEnumerator implements IDictionaryValueEnumerator {
+ private int idx = 0;
+
+ @Override
+ public String current() throws IOException {
+ return null;
+ }
+
+ @Override
+ public boolean moveNext() throws IOException {
+ idx++;
+ if (idx == 1)
+ throw new IOException("read failed.");
+ return true;
+ }
+
+ @Override
+ public void close() throws IOException {
+
+ }
+ }
+}
\ No newline at end of file