diff --git a/client b/client index 94b7bd77ad..e67881a1ef 160000 --- a/client +++ b/client @@ -1 +1 @@ -Subproject commit 94b7bd77adf0620e0eed3547beef91454165af2c +Subproject commit e67881a1ef906710c7363ac271a0b549e903b97e diff --git a/server/odc-core/src/main/java/com/oceanbase/odc/core/authority/session/DefaultSecuritySession.java b/server/odc-core/src/main/java/com/oceanbase/odc/core/authority/session/DefaultSecuritySession.java index 2063aa3657..06d43ae8e7 100644 --- a/server/odc-core/src/main/java/com/oceanbase/odc/core/authority/session/DefaultSecuritySession.java +++ b/server/odc-core/src/main/java/com/oceanbase/odc/core/authority/session/DefaultSecuritySession.java @@ -175,7 +175,6 @@ protected boolean isTimedOut() { protected void validate() throws InvalidSessionException { if (this.isTimedOut()) { - this.expire(); Date lastAccessTime = this.getLastAccessTime(); long timeout = this.getTimeoutMillis(); Serializable sessionId = this.getId(); diff --git a/server/odc-core/src/main/java/com/oceanbase/odc/core/authority/session/manager/BaseSecuritySessionManager.java b/server/odc-core/src/main/java/com/oceanbase/odc/core/authority/session/manager/BaseSecuritySessionManager.java index 3c8308a7b3..1a1c1f36b9 100644 --- a/server/odc-core/src/main/java/com/oceanbase/odc/core/authority/session/manager/BaseSecuritySessionManager.java +++ b/server/odc-core/src/main/java/com/oceanbase/odc/core/authority/session/manager/BaseSecuritySessionManager.java @@ -27,6 +27,7 @@ import org.apache.commons.lang3.Validate; +import com.oceanbase.odc.common.util.ExceptionUtils; import com.oceanbase.odc.core.authority.exception.InvalidSessionException; import com.oceanbase.odc.core.authority.session.DelegateSecuritySession; import com.oceanbase.odc.core.authority.session.SecuritySession; @@ -234,7 +235,9 @@ private void forEachListener(Consumer consumer) { try { consumer.accept(listener); } catch (Throwable e) { - log.warn("Failed to call listener's method", e); + StackTraceElement element = Thread.currentThread().getStackTrace()[2]; + log.warn("Failed to call listener {}#{}, error={}", listener.getClass().getName(), + element.getMethodName(), ExceptionUtils.getRootCauseReason(e)); } } } diff --git a/server/odc-core/src/main/java/com/oceanbase/odc/core/session/BaseConnectionSessionManager.java b/server/odc-core/src/main/java/com/oceanbase/odc/core/session/BaseConnectionSessionManager.java index 50f6c89665..4a47f585f6 100644 --- a/server/odc-core/src/main/java/com/oceanbase/odc/core/session/BaseConnectionSessionManager.java +++ b/server/odc-core/src/main/java/com/oceanbase/odc/core/session/BaseConnectionSessionManager.java @@ -22,6 +22,7 @@ import java.util.function.Consumer; import java.util.function.Predicate; +import com.oceanbase.odc.common.util.ExceptionUtils; import com.oceanbase.odc.core.datasource.DataSourceFactory; import com.oceanbase.odc.core.shared.constant.ConnectType; import com.oceanbase.odc.core.shared.constant.DialectType; @@ -267,7 +268,9 @@ private void forEachListener(Consumer consumer) try { consumer.accept(listener); } catch (Throwable e) { - log.warn("Failed to call listener's method", e); + StackTraceElement element = Thread.currentThread().getStackTrace()[2]; + log.warn("Failed to call listener {}#{}, error={}", listener.getClass().getName(), + element.getMethodName(), ExceptionUtils.getRootCauseReason(e)); } } } diff --git a/server/odc-core/src/main/java/com/oceanbase/odc/core/session/BaseValidatedConnectionSessionManager.java b/server/odc-core/src/main/java/com/oceanbase/odc/core/session/BaseValidatedConnectionSessionManager.java index 2a02fb245d..52e6981e72 100644 --- a/server/odc-core/src/main/java/com/oceanbase/odc/core/session/BaseValidatedConnectionSessionManager.java +++ b/server/odc-core/src/main/java/com/oceanbase/odc/core/session/BaseValidatedConnectionSessionManager.java @@ -49,7 +49,7 @@ public abstract class BaseValidatedConnectionSessionManager extends BaseConnecti private final TaskManager taskManager; @Getter private long scanIntervalMillis = SESSION_MANAGER_SCAN_INTERVAL_MILLIS; - private volatile boolean asynTaskHasBeenStarted = false; + private volatile boolean asyncTaskHasBeenStarted = false; private final List> validators = new LinkedList<>(); public BaseValidatedConnectionSessionManager(@NonNull TaskManager taskManager) { @@ -62,8 +62,8 @@ public void addSessionValidator(@NonNull Predicate predicate) } public synchronized void enableAsyncRefreshSessionManager() { - if (!asynTaskHasBeenStarted) { - asynTaskHasBeenStarted = true; + if (!asyncTaskHasBeenStarted) { + asyncTaskHasBeenStarted = true; taskManager.submit(new ConnectionSessionValidateTask(this, this.validators, scanIntervalMillis)); } } diff --git a/server/odc-core/src/main/java/com/oceanbase/odc/core/session/ConnectionSessionValidateTask.java b/server/odc-core/src/main/java/com/oceanbase/odc/core/session/ConnectionSessionValidateTask.java index d14d8153a5..1933a7300a 100644 --- a/server/odc-core/src/main/java/com/oceanbase/odc/core/session/ConnectionSessionValidateTask.java +++ b/server/odc-core/src/main/java/com/oceanbase/odc/core/session/ConnectionSessionValidateTask.java @@ -60,7 +60,7 @@ public void run() { sessions.stream().filter(s -> that.validatePredicates.stream().anyMatch(p -> !p.test(s))) .forEach(session -> { try { - log.info("Session failed to pass verification, session={}", session); + log.info("Session failed to pass verification, sessionId={}", session.getId()); session.expire(); } catch (Exception e) { log.warn("Failed to remove a session from manager, sessionId={}", session.getId(), e); diff --git a/server/odc-core/src/main/java/com/oceanbase/odc/core/session/DefaultConnectionSession.java b/server/odc-core/src/main/java/com/oceanbase/odc/core/session/DefaultConnectionSession.java index 652bad26c2..a35ac13ce5 100644 --- a/server/odc-core/src/main/java/com/oceanbase/odc/core/session/DefaultConnectionSession.java +++ b/server/odc-core/src/main/java/com/oceanbase/odc/core/session/DefaultConnectionSession.java @@ -29,6 +29,7 @@ import org.apache.commons.io.FileUtils; +import com.oceanbase.odc.common.util.ExceptionUtils; import com.oceanbase.odc.core.datasource.CloneableDataSourceFactory; import com.oceanbase.odc.core.datasource.DataSourceFactory; import com.oceanbase.odc.core.shared.constant.ConnectType; @@ -166,7 +167,8 @@ public synchronized void expire() { this.id, sessionLevelDir); } } catch (IOException exception) { - log.warn("Failed to delete session level directory, dir={}", sessionLevelDir, exception); + log.warn("Failed to delete session level directory, dir={}, sessionId={}", + sessionLevelDir, this.id, exception); } log.info("Connection session was closed successfully, sessionId={}", this.id); } @@ -261,7 +263,6 @@ protected boolean isTimedOut() { protected void validate() throws ExpiredSessionException { if (this.isTimedOut()) { - this.expire(); Date lastAccessTime = this.getLastAccessTime(); long timeout = this.getTimeoutMillis(); Serializable sessionId = this.getId(); @@ -285,9 +286,10 @@ private void closeDataSource() { } try { ((AutoCloseable) dataSource).close(); - log.info("Datasource is closed successfully, name={}", key); + log.info("Datasource is closed successfully, name={}, sessionId={}", key, this.id); } catch (Exception e) { - log.warn("Failed to close dataSource, name={}", key, e); + log.warn("Failed to close dataSource, name={}, sessionId={}, error={}", + key, this.id, ExceptionUtils.getRootCauseReason(e)); } } } @@ -299,8 +301,12 @@ private void closeTaskManager() { } try { taskManager.close(); + if (log.isDebugEnabled()) { + log.debug("TaskManager is closed successfully, sessionId={}", this.id); + } } catch (Exception e) { - log.warn("Failed to close task manager", e); + log.warn("Failed to close the task manager, sessionId={}, error={}", + this.id, ExceptionUtils.getRootCauseReason(e)); } } @@ -314,7 +320,8 @@ private void closeBinaryFileManager() { log.debug("Binary data manager closed successfully, sessionId={}", this.id); } } catch (Exception e) { - log.warn("Binary file manager shutdown failed, sessionId={}, manager={}", this.id, this.dataManager, e); + log.warn("Binary file manager shutdown failed, sessionId={}, manager={}, error={}", + this.id, this.dataManager, ExceptionUtils.getRootCauseReason(e)); } } diff --git a/server/odc-core/src/main/java/com/oceanbase/odc/core/session/DefaultConnectionSessionManager.java b/server/odc-core/src/main/java/com/oceanbase/odc/core/session/DefaultConnectionSessionManager.java index e83920968a..3b83ceed9c 100644 --- a/server/odc-core/src/main/java/com/oceanbase/odc/core/session/DefaultConnectionSessionManager.java +++ b/server/odc-core/src/main/java/com/oceanbase/odc/core/session/DefaultConnectionSessionManager.java @@ -67,13 +67,13 @@ public void onExpireSucceed(ConnectionSession session) { try { this.sessionManager.removeSession(session); } catch (Throwable e) { - log.warn("Fail to delete an expired Session, session={}", session, e); + log.warn("Fail to delete an expired session, sessionId={}", session.getId(), e); } } @Override public void onExpireFailed(ConnectionSession session, Throwable e) { - log.error("Fail to expire a session, session={}", session, e); + log.warn("Failed to expire a session, sessionId={}", session.getId(), e); } } @@ -197,6 +197,8 @@ public void doAction() { ConnectionSession session = this.delayDeleteSessionId2Session.get(this.sessionId); if (session == null) { return; + } else { + this.delayDeleteSessionId2Session.remove(this.sessionId); } session.expire(); log.info("Delayed deletion of connection session successfully, sessionId={}, AET={}", this.sessionId, diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/common/util/SqlUtils.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/common/util/SqlUtils.java index d1ce611f9a..3c3011b933 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/common/util/SqlUtils.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/common/util/SqlUtils.java @@ -117,8 +117,6 @@ public static List splitWithOffset(ConnectionSession connectionSes return split(connectionSession.getDialectType(), processor, sql, removeCommentPrefix); } - - private static List split(DialectType dialectType, SqlCommentProcessor processor, String sql, boolean removeCommentPrefix) { PreConditions.notBlank(processor.getDelimiter(), "delimiter", "Empty or blank delimiter is not allowed"); diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/database/DatabaseService.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/database/DatabaseService.java index 3673596a06..a991cd3269 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/database/DatabaseService.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/database/DatabaseService.java @@ -51,6 +51,8 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; +import com.oceanbase.odc.core.authority.SecurityManager; +import com.oceanbase.odc.core.authority.permission.Permission; import com.oceanbase.odc.core.authority.util.Authenticated; import com.oceanbase.odc.core.authority.util.PreAuthenticate; import com.oceanbase.odc.core.authority.util.SkipAuthorize; @@ -179,10 +181,24 @@ public class DatabaseService { @Autowired private DatabasePermissionHelper databasePermissionHelper; + @Autowired + private SecurityManager securityManager; + @Transactional(rollbackFor = Exception.class) @SkipAuthorize("internal authenticated") public Database detail(@NonNull Long id) { - return getDatabase(id); + Database database = entityToModel(databaseRepository.findById(id) + .orElseThrow(() -> new NotFoundException(ResourceType.ODC_DATABASE, "id", id)), true); + if (Objects.nonNull(database.getProject()) && Objects.nonNull(database.getProject().getId())) { + projectPermissionValidator.checkProjectRole(database.getProject().getId(), ResourceRoleName.all()); + return database; + } + Permission requiredPermission = this.securityManager + .getPermissionByActions(database.getDataSource(), Collections.singletonList("read")); + if (this.securityManager.isPermitted(requiredPermission)) { + return database; + } + throw new NotFoundException(ResourceType.ODC_DATABASE, "id", id); } @SkipAuthorize("odc internal usage") @@ -191,15 +207,6 @@ public Database getBasicSkipPermissionCheck(Long id) { .orElseThrow(() -> new NotFoundException(ResourceType.ODC_DATABASE, "id", id))); } - private Database getDatabase(Long id) { - Database database = entityToModel(databaseRepository.findById(id) - .orElseThrow(() -> new NotFoundException(ResourceType.ODC_DATABASE, "id", id)), true); - if (Objects.nonNull(database.getProject()) && Objects.nonNull(database.getProject().getId())) { - projectPermissionValidator.checkProjectRole(database.getProject().getId(), ResourceRoleName.all()); - } - return database; - } - @SkipAuthorize("odc internal usage") @Transactional(rollbackFor = Exception.class) public ConnectionConfig findDataSourceForConnectById(@NonNull Long id) { diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/session/ConnectConsoleService.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/session/ConnectConsoleService.java index 5d5a9fc5ab..331191d38f 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/session/ConnectConsoleService.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/session/ConnectConsoleService.java @@ -124,7 +124,7 @@ public class ConnectConsoleService { public static final int DEFAULT_GET_RESULT_TIMEOUT_SECONDS = 3; - private static String SHOW_TABLE_COLUMN_INFO = "SHOW_TABLE_COLUMN_INFO"; + private static final String SHOW_TABLE_COLUMN_INFO = "SHOW_TABLE_COLUMN_INFO"; @Autowired private ConnectSessionService sessionService; @Autowired diff --git a/server/plugins/task-plugin-ob-mysql/src/test/java/com/oceanbase/odc/plugin/task/obmysql/partitionplan/OBMySQLHistoricalPartitionPlanDropGeneratorTest.java b/server/plugins/task-plugin-ob-mysql/src/test/java/com/oceanbase/odc/plugin/task/obmysql/partitionplan/OBMySQLHistoricalPartitionPlanDropGeneratorTest.java index 8a7d23cc2b..be9cf2af64 100644 --- a/server/plugins/task-plugin-ob-mysql/src/test/java/com/oceanbase/odc/plugin/task/obmysql/partitionplan/OBMySQLHistoricalPartitionPlanDropGeneratorTest.java +++ b/server/plugins/task-plugin-ob-mysql/src/test/java/com/oceanbase/odc/plugin/task/obmysql/partitionplan/OBMySQLHistoricalPartitionPlanDropGeneratorTest.java @@ -18,8 +18,11 @@ import java.io.IOException; import java.io.InputStream; import java.sql.Connection; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -34,7 +37,9 @@ import org.springframework.jdbc.core.JdbcTemplate; import com.oceanbase.odc.plugin.schema.obmysql.OBMySQLTableExtension; +import com.oceanbase.odc.plugin.task.api.partitionplan.datatype.TimeDataType; import com.oceanbase.odc.plugin.task.api.partitionplan.invoker.drop.DropPartitionGenerator; +import com.oceanbase.odc.plugin.task.api.partitionplan.util.TimeDataTypeUtil; import com.oceanbase.odc.plugin.task.obmysql.partitionplan.invoker.drop.OBMySQLHistoricalPartitionPlanDropGenerator; import com.oceanbase.odc.test.database.TestDBConfiguration; import com.oceanbase.odc.test.database.TestDBConfigurations; @@ -80,7 +85,14 @@ public void generate_datetimeTbl_succeed() throws Exception { List toDelete = generator.invoke(connection, dbTable, getParameters(2, 3)); List actuals = toDelete.stream().map(DBTableAbstractPartitionDefinition::getName) .collect(Collectors.toList()); - Assert.assertEquals(Arrays.asList("p20230901", "p20231001", "p20231101", "p20231201"), actuals); + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.MONTH, -2); + String bound = new SimpleDateFormat("''yyyy-MM-dd HH:mm:ss''") + .format(TimeDataTypeUtil.removeExcessPrecision(calendar.getTime(), TimeDataType.MONTH)); + List expect = dbTable.getPartition().getPartitionDefinitions().stream() + .filter(d -> d.getMaxValues().get(0).compareTo(bound) < 0) + .map(DBTableAbstractPartitionDefinition::getName).collect(Collectors.toList()); + Assert.assertEquals(expect, actuals); } } @@ -95,7 +107,14 @@ public void generate_unixTimestampTbl_succeed() throws Exception { List toDelete = generator.invoke(connection, dbTable, getParameters(2, 3)); List actuals = toDelete.stream().map(DBTableAbstractPartitionDefinition::getName) .collect(Collectors.toList()); - Assert.assertEquals(Arrays.asList("p20230901", "p20231001", "p20231101", "p20231201"), actuals); + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.MONTH, -2); + Date date = TimeDataTypeUtil.removeExcessPrecision(calendar.getTime(), TimeDataType.MONTH); + String bound = date.getTime() / 1000 + ""; + List expect = dbTable.getPartition().getPartitionDefinitions().stream() + .filter(d -> d.getMaxValues().get(0).compareTo(bound) < 0) + .map(DBTableAbstractPartitionDefinition::getName).collect(Collectors.toList()); + Assert.assertEquals(expect, actuals); } }