This is an automated email from the ASF dual-hosted git repository.

qiaojialin pushed a commit to branch rel/0.13
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/rel/0.13 by this push:
     new feb24d0d10 [To rel/0.13][IOTDB-3843] Refine the using of setting 
read-only (#6773)
feb24d0d10 is described below

commit feb24d0d10414fd354de1a21b1f2ce4c4a730e9f
Author: Alan Choo <[email protected]>
AuthorDate: Thu Jul 28 14:27:57 2022 +0800

    [To rel/0.13][IOTDB-3843] Refine the using of setting read-only (#6773)
---
 .../iotdb/db/integration/IoTDBRestartIT.java       |  3 +-
 .../resources/conf/iotdb-engine.properties         |  4 ++
 .../java/org/apache/iotdb/db/conf/IoTDBConfig.java | 44 ++++++++++++++++++--
 .../org/apache/iotdb/db/conf/IoTDBDescriptor.java  |  6 +++
 .../org/apache/iotdb/db/conf/SystemStatus.java     | 32 +++++++++++++++
 .../directories/strategy/DirectoryStrategy.java    |  4 +-
 .../db/engine/storagegroup/TsFileProcessor.java    | 43 ++++++++++++++------
 .../storagegroup/VirtualStorageGroupProcessor.java | 47 +++++++++++++---------
 .../iotdb/db/metadata/logfile/MLogWriter.java      | 25 +++++++++---
 .../apache/iotdb/db/qp/constant/SQLConstant.java   |  3 +-
 .../apache/iotdb/db/qp/executor/PlanExecutor.java  |  5 ++-
 .../apache/iotdb/db/qp/physical/sys/ShowPlan.java  |  2 +-
 .../db/service/thrift/impl/TSServiceImpl.java      |  8 ++++
 .../db/writelog/node/ExclusiveWriteLogNode.java    |  5 ++-
 .../apache/iotdb/db/utils/EnvironmentUtils.java    |  3 +-
 .../java/org/apache/iotdb/session/Session.java     |  5 +++
 .../apache/iotdb/session/SessionConnection.java    | 20 +++++++++
 .../org/apache/iotdb/session/pool/SessionPool.java | 19 +++++++++
 .../apache/iotdb/session/util/SystemStatus.java    | 32 +++++++++++++++
 .../apache/iotdb/spark/db/EnvironmentUtils.java    |  3 +-
 thrift/src/main/thrift/rpc.thrift                  |  7 ++++
 21 files changed, 268 insertions(+), 52 deletions(-)

diff --git 
a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBRestartIT.java 
b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBRestartIT.java
index c6984d9f23..7fe9384e0e 100644
--- 
a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBRestartIT.java
+++ 
b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBRestartIT.java
@@ -20,6 +20,7 @@ package org.apache.iotdb.db.integration;
 
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.conf.SystemStatus;
 import org.apache.iotdb.db.engine.StorageEngine;
 import org.apache.iotdb.db.engine.memtable.IMemTable;
 import org.apache.iotdb.db.engine.storagegroup.TsFileProcessor;
@@ -423,7 +424,7 @@ public class IoTDBRestartIT {
       statement.execute("flush");
     }
 
-    IoTDBDescriptor.getInstance().getConfig().setReadOnly(false);
+    
IoTDBDescriptor.getInstance().getConfig().setSystemStatus(SystemStatus.NORMAL);
     EnvironmentUtils.restartDaemon();
 
     try (Connection connection =
diff --git a/server/src/assembly/resources/conf/iotdb-engine.properties 
b/server/src/assembly/resources/conf/iotdb-engine.properties
index afa416c129..840a3b6ad0 100644
--- a/server/src/assembly/resources/conf/iotdb-engine.properties
+++ b/server/src/assembly/resources/conf/iotdb-engine.properties
@@ -193,6 +193,10 @@ timestamp_precision=ms
 # Datatype: long
 # default_ttl=36000000
 
+# Shutdown system or set it to read-only mode when unrecoverable error occurs.
+# Datatype: bool
+# allow_read_only_when_errors_occur=true
+
 # The size of the log buffer in each log node (in bytes). Due to the double 
buffer mechanism,
 # if WAL is enabled and the size of the inserted plan is greater than one-half 
of this parameter,
 # then the insert plan will be rejected by WAL.
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java 
b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
index d33e8a0ff3..16c7151e95 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
@@ -141,7 +141,11 @@ public class IoTDBConfig {
   /** Is the write ahead log enable. */
   private boolean enableWal = true;
 
-  private volatile boolean readOnly = false;
+  /** Shutdown system or set it to read-only mode when unrecoverable error 
occurs. */
+  private boolean allowReadOnlyWhenErrorsOccur = true;
+
+  /** Status of current system. */
+  private volatile SystemStatus status = SystemStatus.NORMAL;
 
   private boolean enableDiscardOutOfOrderData = false;
 
@@ -1384,12 +1388,44 @@ public class IoTDBConfig {
     this.sessionTimeoutThreshold = sessionTimeoutThreshold;
   }
 
+  boolean isAllowReadOnlyWhenErrorsOccur() {
+    return allowReadOnlyWhenErrorsOccur;
+  }
+
+  void setAllowReadOnlyWhenErrorsOccur(boolean allowReadOnlyWhenErrorsOccur) {
+    this.allowReadOnlyWhenErrorsOccur = allowReadOnlyWhenErrorsOccur;
+  }
+
   public boolean isReadOnly() {
-    return readOnly;
+    return status == SystemStatus.READ_ONLY
+        || (status == SystemStatus.ERROR && allowReadOnlyWhenErrorsOccur);
+  }
+
+  public SystemStatus getSystemStatus() {
+    return status;
   }
 
-  public void setReadOnly(boolean readOnly) {
-    this.readOnly = readOnly;
+  public void setSystemStatus(SystemStatus newStatus) {
+    if (newStatus == SystemStatus.READ_ONLY) {
+      logger.error(
+          "Change system mode to read-only! Only query statements are 
permitted!",
+          new RuntimeException("System mode is set to READ_ONLY"));
+    } else if (newStatus == SystemStatus.ERROR) {
+      if (allowReadOnlyWhenErrorsOccur) {
+        logger.error(
+            "Unrecoverable error occurs! Make system read-only when 
allow_read_only_when_errors_occur is true.",
+            new RuntimeException("System mode is set to READ_ONLY"));
+        newStatus = SystemStatus.READ_ONLY;
+      } else {
+        logger.error(
+            "Unrecoverable error occurs! Shutdown system directly when 
allow_read_only_when_errors_occur is false.",
+            new RuntimeException("System mode is set to ERROR"));
+        System.exit(-1);
+      }
+    } else {
+      logger.warn("Set system mode from {} to {}.", status, newStatus);
+    }
+    this.status = newStatus;
   }
 
   public String getRpcImplClassName() {
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java 
b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
index 5ff5d12683..8d1f1f9b8e 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
@@ -620,6 +620,12 @@ public class IoTDBDescriptor {
           Long.parseLong(
               properties.getProperty("default_ttl", 
String.valueOf(conf.getDefaultTTL()))));
 
+      conf.setAllowReadOnlyWhenErrorsOccur(
+          Boolean.parseBoolean(
+              properties.getProperty(
+                  "allow_read_only_when_errors_occur",
+                  String.valueOf(conf.isAllowReadOnlyWhenErrorsOccur()))));
+
       // the num of memtables in each storage group
       conf.setConcurrentWritingTimePartition(
           Integer.parseInt(
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/SystemStatus.java 
b/server/src/main/java/org/apache/iotdb/db/conf/SystemStatus.java
new file mode 100644
index 0000000000..745fbb1529
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/conf/SystemStatus.java
@@ -0,0 +1,32 @@
+/*
+ * 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.iotdb.db.conf;
+
+/** Status of current system */
+public enum SystemStatus {
+  /** System can read and write normally */
+  NORMAL,
+  /** Only query statements are permitted */
+  READ_ONLY,
+  /**
+   * Unrecoverable errors occur, system will be read-only or exit according to 
the param
+   * allow_read_only_when_errors_occur
+   */
+  ERROR,
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/conf/directories/strategy/DirectoryStrategy.java
 
b/server/src/main/java/org/apache/iotdb/db/conf/directories/strategy/DirectoryStrategy.java
index b0558993b4..ddbac482d8 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/conf/directories/strategy/DirectoryStrategy.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/conf/directories/strategy/DirectoryStrategy.java
@@ -19,6 +19,7 @@
 package org.apache.iotdb.db.conf.directories.strategy;
 
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.conf.SystemStatus;
 import org.apache.iotdb.db.exception.DiskSpaceInsufficientException;
 import org.apache.iotdb.db.utils.CommonUtils;
 
@@ -54,7 +55,8 @@ public abstract class DirectoryStrategy {
       }
     }
     if (!hasSpace) {
-      IoTDBDescriptor.getInstance().getConfig().setReadOnly(true);
+      logger.error("Disk space is insufficient, change system mode to 
read-only");
+      
IoTDBDescriptor.getInstance().getConfig().setSystemStatus(SystemStatus.READ_ONLY);
       throw new DiskSpaceInsufficientException(folders);
     }
 
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
index 4bc9ab6ce4..e21c710c36 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
@@ -20,6 +20,7 @@ package org.apache.iotdb.db.engine.storagegroup;
 
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.conf.SystemStatus;
 import org.apache.iotdb.db.conf.adapter.CompressionRatio;
 import org.apache.iotdb.db.engine.StorageEngine;
 import org.apache.iotdb.db.engine.flush.CloseFileListener;
@@ -1042,11 +1043,11 @@ public class TsFileProcessor {
           }
         } else {
           logger.error(
-              "{}: {} meet error when flushing a memtable, change system mode 
to read-only",
+              "{}: {} meet error when flushing a memtable, change system mode 
to error",
               storageGroupName,
               tsFileResource.getTsFile().getName(),
               e);
-          IoTDBDescriptor.getInstance().getConfig().setReadOnly(true);
+          
IoTDBDescriptor.getInstance().getConfig().setSystemStatus(SystemStatus.ERROR);
           try {
             logger.error(
                 "{}: {} IOTask meets error, truncate the corrupted data",
@@ -1132,7 +1133,9 @@ public class TsFileProcessor {
     // for sync flush
     syncReleaseFlushedMemTable(memTableToFlush);
 
-    if (shouldClose && flushingMemTables.isEmpty() && writer != null) {
+    // retry to avoid unnecessary read-only mode
+    int retryCnt = 0;
+    while (shouldClose && flushingMemTables.isEmpty() && writer != null) {
       try {
         writer.mark();
         updateCompressionRatio(memTableToFlush);
@@ -1140,7 +1143,7 @@ public class TsFileProcessor {
           logger.debug(
               "{}: {} flushingMemtables is empty and will close the file",
               storageGroupName,
-              tsFileResource.getTsFile().getName());
+              tsFileResource.getTsFile().getAbsolutePath());
         }
         endFile();
         if (logger.isDebugEnabled()) {
@@ -1148,36 +1151,50 @@ public class TsFileProcessor {
         }
       } catch (Exception e) {
         logger.error(
-            "{} meet error when flush FileMetadata to {}, change system mode 
to read-only",
+            "{}: {} marking or ending file meet error",
             storageGroupName,
             tsFileResource.getTsFile().getAbsolutePath(),
             e);
-        IoTDBDescriptor.getInstance().getConfig().setReadOnly(true);
+        // truncate broken metadata
         try {
           writer.reset();
         } catch (IOException e1) {
           logger.error(
               "{}: {} truncate corrupted data meets error",
               storageGroupName,
-              tsFileResource.getTsFile().getName(),
+              tsFileResource.getTsFile().getAbsolutePath(),
               e1);
         }
-        logger.error(
-            "{}: {} marking or ending file meet error",
-            storageGroupName,
-            tsFileResource.getTsFile().getName(),
-            e);
+        // retry or set read-only
+        if (retryCnt < 3) {
+          logger.warn(
+              "{} meet error when flush FileMetadata to {}, retry it again",
+              storageGroupName,
+              tsFileResource.getTsFile().getAbsolutePath(),
+              e);
+          retryCnt++;
+          continue;
+        } else {
+          logger.error(
+              "{} meet error when flush FileMetadata to {}, change system mode 
to error",
+              storageGroupName,
+              tsFileResource.getTsFile().getAbsolutePath(),
+              e);
+          
IoTDBDescriptor.getInstance().getConfig().setSystemStatus(SystemStatus.ERROR);
+          break;
+        }
       }
       // for sync close
       if (logger.isDebugEnabled()) {
         logger.debug(
             "{}: {} try to get flushingMemtables lock.",
             storageGroupName,
-            tsFileResource.getTsFile().getName());
+            tsFileResource.getTsFile().getAbsolutePath());
       }
       synchronized (flushingMemTables) {
         flushingMemTables.notifyAll();
       }
+      break;
     }
   }
 
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/VirtualStorageGroupProcessor.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/VirtualStorageGroupProcessor.java
index 583bc30b32..d6f9c8f5a7 100755
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/VirtualStorageGroupProcessor.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/VirtualStorageGroupProcessor.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.db.concurrent.ThreadName;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBConstant;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.conf.SystemStatus;
 import org.apache.iotdb.db.conf.directories.DirectoryManager;
 import org.apache.iotdb.db.engine.StorageEngine;
 import org.apache.iotdb.db.engine.compaction.CompactionScheduler;
@@ -1192,24 +1193,34 @@ public class VirtualStorageGroupProcessor {
 
   private TsFileProcessor getOrCreateTsFileProcessor(long timeRangeId, boolean 
sequence) {
     TsFileProcessor tsFileProcessor = null;
-    try {
-      if (sequence) {
-        tsFileProcessor =
-            getOrCreateTsFileProcessorIntern(timeRangeId, 
workSequenceTsFileProcessors, true);
-      } else {
-        tsFileProcessor =
-            getOrCreateTsFileProcessorIntern(timeRangeId, 
workUnsequenceTsFileProcessors, false);
+    int retryCnt = 0;
+    do {
+      try {
+        if (sequence) {
+          tsFileProcessor =
+              getOrCreateTsFileProcessorIntern(timeRangeId, 
workSequenceTsFileProcessors, true);
+        } else {
+          tsFileProcessor =
+              getOrCreateTsFileProcessorIntern(timeRangeId, 
workUnsequenceTsFileProcessors, false);
+        }
+      } catch (DiskSpaceInsufficientException e) {
+        logger.error(
+            "disk space is insufficient when creating TsFile processor, change 
system mode to read-only",
+            e);
+        
IoTDBDescriptor.getInstance().getConfig().setSystemStatus(SystemStatus.READ_ONLY);
+        break;
+      } catch (IOException e) {
+        if (retryCnt < 3) {
+          logger.warn("meet IOException when creating TsFileProcessor, retry 
it again", e);
+          retryCnt++;
+        } else {
+          logger.error(
+              "meet IOException when creating TsFileProcessor, change system 
mode to error", e);
+          
IoTDBDescriptor.getInstance().getConfig().setSystemStatus(SystemStatus.ERROR);
+          break;
+        }
       }
-    } catch (DiskSpaceInsufficientException e) {
-      logger.error(
-          "disk space is insufficient when creating TsFile processor, change 
system mode to read-only",
-          e);
-      IoTDBDescriptor.getInstance().getConfig().setReadOnly(true);
-    } catch (IOException e) {
-      logger.error(
-          "meet IOException when creating TsFileProcessor, change system mode 
to read-only", e);
-      IoTDBDescriptor.getInstance().getConfig().setReadOnly(true);
-    }
+    } while (tsFileProcessor == null);
     return tsFileProcessor;
   }
 
@@ -2302,7 +2313,6 @@ public class VirtualStorageGroupProcessor {
           "Failed to append the tsfile {} to storage group processor {} 
because the disk space is insufficient.",
           tsfileToBeInserted.getAbsolutePath(),
           tsfileToBeInserted.getParentFile().getName());
-      IoTDBDescriptor.getInstance().getConfig().setReadOnly(true);
       throw new LoadFileException(e);
     } catch (IllegalPathException e) {
       logger.error(
@@ -2385,7 +2395,6 @@ public class VirtualStorageGroupProcessor {
           "Failed to append the tsfile {} to storage group processor {} 
because the disk space is insufficient.",
           tsfileToBeInserted.getAbsolutePath(),
           tsfileToBeInserted.getParentFile().getName());
-      IoTDBDescriptor.getInstance().getConfig().setReadOnly(true);
       throw new LoadFileException(e);
     } catch (IllegalPathException e) {
       logger.error(
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogWriter.java 
b/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogWriter.java
index 15aa3a704c..1ec1e16d7e 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogWriter.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogWriter.java
@@ -20,6 +20,7 @@ package org.apache.iotdb.db.metadata.logfile;
 
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.conf.SystemStatus;
 import org.apache.iotdb.db.engine.fileSystem.SystemFileFactory;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
 import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
@@ -101,12 +102,24 @@ public class MLogWriter implements AutoCloseable {
   }
 
   private void sync() {
-    try {
-      logWriter.write(mlogBuffer);
-    } catch (IOException e) {
-      logger.error(
-          "MLog {} sync failed, change system mode to read-only", 
logFile.getAbsoluteFile(), e);
-      IoTDBDescriptor.getInstance().getConfig().setReadOnly(true);
+    int retryCnt = 0;
+    mlogBuffer.mark();
+    while (true) {
+      try {
+        logWriter.write(mlogBuffer);
+        break;
+      } catch (IOException e) {
+        if (retryCnt < 3) {
+          logger.warn("MLog {} sync failed, retry it again", 
logFile.getAbsoluteFile(), e);
+          mlogBuffer.reset();
+          retryCnt++;
+        } else {
+          logger.error(
+              "MLog {} sync failed, change system mode to error", 
logFile.getAbsoluteFile(), e);
+          
IoTDBDescriptor.getInstance().getConfig().setSystemStatus(SystemStatus.ERROR);
+          break;
+        }
+      }
     }
     mlogBuffer.clear();
   }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java 
b/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java
index b137ddd9b2..d63595d5e9 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java
@@ -197,9 +197,8 @@ public class SQLConstant {
   public static final int TOK_SCHEMA_TEMPLATE_SHOW_NODES = 120;
   public static final int TOK_SCHEMA_TEMPLATE_SHOW_PATHS_SET = 121;
   public static final int TOK_SCHEMA_TEMPLATE_SHOW_PATHS_USING = 122;
-  public static final int TOK_SCHEMA_TEMPLATE_DEACTIVATE = 124;
-
   public static final int TOK_SHOW_QUERY_RESOURCE = 123;
+  public static final int TOK_SCHEMA_TEMPLATE_DEACTIVATE = 124;
 
   public static final Map<Integer, String> tokenNames = new HashMap<>();
 
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java 
b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
index 5b8a0bcbfe..ab2a539aed 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
@@ -30,6 +30,7 @@ import org.apache.iotdb.db.concurrent.IoTDBThreadPoolFactory;
 import org.apache.iotdb.db.concurrent.ThreadName;
 import org.apache.iotdb.db.conf.IoTDBConstant;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.conf.SystemStatus;
 import org.apache.iotdb.db.engine.StorageEngine;
 import org.apache.iotdb.db.engine.cache.BloomFilterCache;
 import org.apache.iotdb.db.engine.cache.ChunkCache;
@@ -601,7 +602,9 @@ public class PlanExecutor implements IPlanExecutor {
   }
 
   private void operateSetSystemMode(SetSystemModePlan plan) {
-    IoTDBDescriptor.getInstance().getConfig().setReadOnly(plan.isReadOnly());
+    IoTDBDescriptor.getInstance()
+        .getConfig()
+        .setSystemStatus(plan.isReadOnly() ? SystemStatus.READ_ONLY : 
SystemStatus.NORMAL);
   }
 
   private void operateFlush(FlushPlan plan) throws StorageGroupNotSetException 
{
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/ShowPlan.java 
b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/ShowPlan.java
index 8cf733739b..021814e1b8 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/ShowPlan.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/ShowPlan.java
@@ -126,6 +126,6 @@ public class ShowPlan extends PhysicalPlan {
     SCHEMA_TEMPLATE,
     NODES_IN_SCHEMA_TEMPLATE,
     PATHS_SET_SCHEMA_TEMPLATE,
-    PATHS_USING_SCHEMA_TEMPLATE
+    PATHS_USING_SCHEMA_TEMPLATE,
   }
 }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/TSServiceImpl.java
 
b/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/TSServiceImpl.java
index 534ac9915b..0d44a4785a 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/TSServiceImpl.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/TSServiceImpl.java
@@ -101,6 +101,7 @@ import 
org.apache.iotdb.service.rpc.thrift.TSFetchMetadataReq;
 import org.apache.iotdb.service.rpc.thrift.TSFetchMetadataResp;
 import org.apache.iotdb.service.rpc.thrift.TSFetchResultsReq;
 import org.apache.iotdb.service.rpc.thrift.TSFetchResultsResp;
+import org.apache.iotdb.service.rpc.thrift.TSGetSystemStatusResp;
 import org.apache.iotdb.service.rpc.thrift.TSGetTimeZoneResp;
 import org.apache.iotdb.service.rpc.thrift.TSIService;
 import org.apache.iotdb.service.rpc.thrift.TSInsertRecordReq;
@@ -1132,6 +1133,13 @@ public class TSServiceImpl implements TSIService.Iface {
     }
   }
 
+  @Override
+  public TSGetSystemStatusResp getSystemStatus(long sessionId) {
+    return new TSGetSystemStatusResp(
+        RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS),
+        
IoTDBDescriptor.getInstance().getConfig().getSystemStatus().toString());
+  }
+
   @Override
   public TSGetTimeZoneResp getTimeZone(long sessionId) {
     try {
diff --git 
a/server/src/main/java/org/apache/iotdb/db/writelog/node/ExclusiveWriteLogNode.java
 
b/server/src/main/java/org/apache/iotdb/db/writelog/node/ExclusiveWriteLogNode.java
index 79e12b82d9..4dfcc3406c 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/writelog/node/ExclusiveWriteLogNode.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/writelog/node/ExclusiveWriteLogNode.java
@@ -21,6 +21,7 @@ package org.apache.iotdb.db.writelog.node;
 import org.apache.iotdb.db.concurrent.IoTDBThreadPoolFactory;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.conf.SystemStatus;
 import org.apache.iotdb.db.conf.directories.DirectoryManager;
 import org.apache.iotdb.db.engine.fileSystem.SystemFileFactory;
 import org.apache.iotdb.db.qp.physical.PhysicalPlan;
@@ -316,8 +317,8 @@ public class ExclusiveWriteLogNode implements WriteLogNode, 
Comparable<Exclusive
     try {
       writer.write(logBufferFlushing);
     } catch (Throwable e) {
-      logger.error("Log node {} sync failed, change system mode to read-only", 
identifier, e);
-      IoTDBDescriptor.getInstance().getConfig().setReadOnly(true);
+      logger.error("Log node {} sync failed, change system mode to error", 
identifier, e);
+      
IoTDBDescriptor.getInstance().getConfig().setSystemStatus(SystemStatus.ERROR);
     } finally {
       // switch buffer flushing to idle and notify the sync thread
       synchronized (switchBufferCondition) {
diff --git 
a/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java 
b/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java
index f60c73e85f..f41ca37f9b 100644
--- a/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java
+++ b/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java
@@ -22,6 +22,7 @@ import org.apache.iotdb.db.auth.AuthException;
 import org.apache.iotdb.db.auth.authorizer.BasicAuthorizer;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.conf.SystemStatus;
 import org.apache.iotdb.db.conf.directories.DirectoryManager;
 import org.apache.iotdb.db.constant.TestConstant;
 import org.apache.iotdb.db.engine.StorageEngine;
@@ -141,7 +142,7 @@ public class EnvironmentUtils {
       fail();
     }
 
-    IoTDBDescriptor.getInstance().getConfig().setReadOnly(false);
+    
IoTDBDescriptor.getInstance().getConfig().setSystemStatus(SystemStatus.NORMAL);
     // We must disable MQTT service as it will cost a lot of time to be 
shutdown, which may slow our
     // unit tests.
     IoTDBDescriptor.getInstance().getConfig().setEnableMQTTService(false);
diff --git a/session/src/main/java/org/apache/iotdb/session/Session.java 
b/session/src/main/java/org/apache/iotdb/session/Session.java
index 5025a8f230..828540fe57 100644
--- a/session/src/main/java/org/apache/iotdb/session/Session.java
+++ b/session/src/main/java/org/apache/iotdb/session/Session.java
@@ -50,6 +50,7 @@ import org.apache.iotdb.session.template.MeasurementNode;
 import org.apache.iotdb.session.template.Template;
 import org.apache.iotdb.session.template.TemplateQueryType;
 import org.apache.iotdb.session.util.SessionUtils;
+import org.apache.iotdb.session.util.SystemStatus;
 import org.apache.iotdb.session.util.ThreadUtils;
 import org.apache.iotdb.session.util.Version;
 import org.apache.iotdb.tsfile.exception.write.UnSupportedDataTypeException;
@@ -421,6 +422,10 @@ public class Session {
     return new SessionConnection(session, endpoint, zoneId);
   }
 
+  public SystemStatus getSystemStatus() throws IoTDBConnectionException {
+    return defaultSessionConnection.getSystemStatus();
+  }
+
   public synchronized String getTimeZone() {
     return defaultSessionConnection.getTimeZone();
   }
diff --git 
a/session/src/main/java/org/apache/iotdb/session/SessionConnection.java 
b/session/src/main/java/org/apache/iotdb/session/SessionConnection.java
index 06a960b21a..ed6cf16ebb 100644
--- a/session/src/main/java/org/apache/iotdb/session/SessionConnection.java
+++ b/session/src/main/java/org/apache/iotdb/session/SessionConnection.java
@@ -36,6 +36,7 @@ import org.apache.iotdb.service.rpc.thrift.TSDeleteDataReq;
 import org.apache.iotdb.service.rpc.thrift.TSDropSchemaTemplateReq;
 import org.apache.iotdb.service.rpc.thrift.TSExecuteStatementReq;
 import org.apache.iotdb.service.rpc.thrift.TSExecuteStatementResp;
+import org.apache.iotdb.service.rpc.thrift.TSGetSystemStatusResp;
 import org.apache.iotdb.service.rpc.thrift.TSIService;
 import org.apache.iotdb.service.rpc.thrift.TSInsertRecordReq;
 import org.apache.iotdb.service.rpc.thrift.TSInsertRecordsOfOneDeviceReq;
@@ -59,6 +60,7 @@ import 
org.apache.iotdb.service.rpc.thrift.TSSetUsingTemplateReq;
 import org.apache.iotdb.service.rpc.thrift.TSStatus;
 import org.apache.iotdb.service.rpc.thrift.TSUnsetSchemaTemplateReq;
 import org.apache.iotdb.session.util.SessionUtils;
+import org.apache.iotdb.session.util.SystemStatus;
 
 import org.apache.thrift.TException;
 import org.apache.thrift.protocol.TBinaryProtocol;
@@ -200,6 +202,24 @@ public class SessionConnection {
     return client;
   }
 
+  protected SystemStatus getSystemStatus() throws IoTDBConnectionException {
+    TSGetSystemStatusResp resp;
+    try {
+      resp = client.getSystemStatus(sessionId);
+    } catch (TException e) {
+      if (reconnect()) {
+        try {
+          resp = client.getSystemStatus(sessionId);
+        } catch (TException tException) {
+          throw new IoTDBConnectionException(tException);
+        }
+      } else {
+        throw new IoTDBConnectionException(logForReconnectionFailure());
+      }
+    }
+    return SystemStatus.valueOf(resp.getSystemStatus());
+  }
+
   protected void setTimeZone(String zoneId)
       throws StatementExecutionException, IoTDBConnectionException {
     TSSetTimeZoneReq req = new TSSetTimeZoneReq(sessionId, zoneId);
diff --git 
a/session/src/main/java/org/apache/iotdb/session/pool/SessionPool.java 
b/session/src/main/java/org/apache/iotdb/session/pool/SessionPool.java
index 82fc8107aa..326f6c4030 100644
--- a/session/src/main/java/org/apache/iotdb/session/pool/SessionPool.java
+++ b/session/src/main/java/org/apache/iotdb/session/pool/SessionPool.java
@@ -24,6 +24,7 @@ import org.apache.iotdb.session.Config;
 import org.apache.iotdb.session.Session;
 import org.apache.iotdb.session.SessionDataSet;
 import org.apache.iotdb.session.template.Template;
+import org.apache.iotdb.session.util.SystemStatus;
 import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
@@ -2322,6 +2323,24 @@ public class SessionPool {
     return false;
   }
 
+  public SystemStatus getSystemStatus() throws IoTDBConnectionException {
+    for (int i = 0; i < RETRY; i++) {
+      Session session = getSession();
+      try {
+        SystemStatus status = session.getSystemStatus();
+        putBack(session);
+        return status;
+      } catch (IoTDBConnectionException e) {
+        // TException means the connection is broken, remove it and get a new 
one.
+        cleanSessionAndMayThrowConnectionException(session, i, e);
+      } catch (RuntimeException e) {
+        putBack(session);
+        throw e;
+      }
+    }
+    return null;
+  }
+
   public int getMaxSize() {
     return maxSize;
   }
diff --git 
a/session/src/main/java/org/apache/iotdb/session/util/SystemStatus.java 
b/session/src/main/java/org/apache/iotdb/session/util/SystemStatus.java
new file mode 100644
index 0000000000..ad383dbfcb
--- /dev/null
+++ b/session/src/main/java/org/apache/iotdb/session/util/SystemStatus.java
@@ -0,0 +1,32 @@
+/*
+ * 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.iotdb.session.util;
+
+/** Status of current system */
+public enum SystemStatus {
+  /** System can read and write normally */
+  NORMAL,
+  /** Only query statements are permitted */
+  READ_ONLY,
+  /**
+   * Unrecoverable errors occur, system will be read-only or exit according to 
the param
+   * allow_read_only_when_errors_occur
+   */
+  ERROR,
+}
diff --git 
a/spark-iotdb-connector/src/test/scala/org/apache/iotdb/spark/db/EnvironmentUtils.java
 
b/spark-iotdb-connector/src/test/scala/org/apache/iotdb/spark/db/EnvironmentUtils.java
index 5f54ad3b46..a7845851da 100644
--- 
a/spark-iotdb-connector/src/test/scala/org/apache/iotdb/spark/db/EnvironmentUtils.java
+++ 
b/spark-iotdb-connector/src/test/scala/org/apache/iotdb/spark/db/EnvironmentUtils.java
@@ -31,6 +31,7 @@ import org.apache.iotdb.db.auth.authorizer.BasicAuthorizer;
 import org.apache.iotdb.db.auth.authorizer.IAuthorizer;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.conf.SystemStatus;
 import org.apache.iotdb.db.conf.directories.DirectoryManager;
 import org.apache.iotdb.db.engine.StorageEngine;
 import org.apache.iotdb.db.engine.cache.BloomFilterCache;
@@ -111,7 +112,7 @@ public class EnvironmentUtils {
       Assert.fail();
     }
     StorageEngine.getInstance().reset();
-    IoTDBDescriptor.getInstance().getConfig().setReadOnly(false);
+    
IoTDBDescriptor.getInstance().getConfig().setSystemStatus(SystemStatus.NORMAL);
 
     // clean wal
     MultiFileLogNodeManager.getInstance().stop();
diff --git a/thrift/src/main/thrift/rpc.thrift 
b/thrift/src/main/thrift/rpc.thrift
index 797270e180..fbcabef7f2 100644
--- a/thrift/src/main/thrift/rpc.thrift
+++ b/thrift/src/main/thrift/rpc.thrift
@@ -200,6 +200,11 @@ struct TSFetchMetadataReq{
   3: optional string columnPath
 }
 
+struct TSGetSystemStatusResp {
+  1: required TSStatus status
+  2: required string systemStatus
+}
+
 struct TSGetTimeZoneResp {
   1: required TSStatus status
   2: required string timeZone
@@ -448,6 +453,8 @@ service TSIService {
 
   TSStatus closeOperation(1:TSCloseOperationReq req);
 
+  TSGetSystemStatusResp getSystemStatus(1:i64 sessionId);
+
   TSGetTimeZoneResp getTimeZone(1:i64 sessionId);
 
   TSStatus setTimeZone(1:TSSetTimeZoneReq req);

Reply via email to