keycloak
公開メンバ関数 | 静的非公開変数類 | 全メンバ一覧
org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockService クラス
org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockService の継承関係図
Inheritance graph
org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockService 連携図
Collaboration graph

公開メンバ関数

void init () throws DatabaseException
 
void waitForLock ()
 
boolean acquireLock ()
 
void releaseLock ()
 

静的非公開変数類

static final Logger log = Logger.getLogger(CustomLockService.class)
 

詳解

Liquibase lock service, which has some bugfixes and assumes timeouts to be configured in milliseconds

著者
Marek Posolda

関数詳解

◆ acquireLock()

boolean org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockService.acquireLock ( )
inline
143  {
144  if (hasChangeLogLock) {
145  // We already have a lock
146  return true;
147  }
148 
149  Executor executor = ExecutorService.getInstance().getExecutor(database);
150 
151  try {
152  database.rollback();
153 
154  // Ensure table created and lock record inserted
155  this.init();
156  } catch (DatabaseException de) {
157  throw new IllegalStateException("Failed to retrieve lock", de);
158  }
159 
160  try {
161  log.debug("Trying to lock database");
162  executor.execute(new LockDatabaseChangeLogStatement());
163  log.debug("Successfully acquired database lock");
164 
165  hasChangeLogLock = true;
166  database.setCanCacheLiquibaseTableInfo(true);
167  return true;
168 
169  } catch (DatabaseException de) {
170  log.warn("Lock didn't yet acquired. Will possibly retry to acquire lock. Details: " + de.getMessage());
171  if (log.isTraceEnabled()) {
172  log.debug(de.getMessage(), de);
173  }
174  return false;
175  }
176  }
static final Logger log
Definition: CustomLockService.java:43

◆ init()

void org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockService.init ( ) throws DatabaseException
inline
46  {
47  boolean createdTable = false;
48  Executor executor = ExecutorService.getInstance().getExecutor(database);
49 
50  if (!hasDatabaseChangeLogLockTable()) {
51 
52  try {
53  if (log.isTraceEnabled()) {
54  log.trace("Create Database Lock Table");
55  }
56  executor.execute(new CreateDatabaseChangeLogLockTableStatement());
57  database.commit();
58  } catch (DatabaseException de) {
59  log.warn("Failed to create lock table. Maybe other transaction created in the meantime. Retrying...");
60  if (log.isTraceEnabled()) {
61  log.trace(de.getMessage(), de); //Log details at trace level
62  }
63  database.rollback();
64  throw new LockRetryException(de);
65  }
66 
67  log.debugf("Created database lock table with name: %s", database.escapeTableName(database.getLiquibaseCatalogName(), database.getLiquibaseSchemaName(), database.getDatabaseChangeLogLockTableName()));
68 
69  try {
70  Field field = Reflections.findDeclaredField(StandardLockService.class, "hasDatabaseChangeLogLockTable");
71  Reflections.setAccessible(field);
72  field.set(CustomLockService.this, true);
73  } catch (IllegalAccessException iae) {
74  throw new RuntimeException(iae);
75  }
76 
77  createdTable = true;
78  }
79 
80 
81  if (!isDatabaseChangeLogLockTableInitialized(createdTable)) {
82  try {
83  if (log.isTraceEnabled()) {
84  log.trace("Initialize Database Lock Table");
85  }
86  executor.execute(new InitializeDatabaseChangeLogLockTableStatement());
87  database.commit();
88 
89  } catch (DatabaseException de) {
90  log.warn("Failed to insert first record to the lock table. Maybe other transaction inserted in the meantime. Retrying...");
91  if (log.isTraceEnabled()) {
92  log.trace(de.getMessage(), de); // Log details at trace level
93  }
94  database.rollback();
95  throw new LockRetryException(de);
96  }
97 
98  log.debug("Initialized record in the database lock table");
99  }
100 
101 
102  // Keycloak doesn't support Derby, but keep it for sure...
103  if (executor.updatesDatabase() && database instanceof DerbyDatabase && ((DerbyDatabase) database).supportsBooleanDataType()) { //check if the changelog table is of an old smallint vs. boolean format
104  String lockTable = database.escapeTableName(database.getLiquibaseCatalogName(), database.getLiquibaseSchemaName(), database.getDatabaseChangeLogLockTableName());
105  Object obj = executor.queryForObject(new RawSqlStatement("select min(locked) as test from " + lockTable + " fetch first row only"), Object.class);
106  if (!(obj instanceof Boolean)) { //wrong type, need to recreate table
107  executor.execute(new DropTableStatement(database.getLiquibaseCatalogName(), database.getLiquibaseSchemaName(), database.getDatabaseChangeLogLockTableName(), false));
108  executor.execute(new CreateDatabaseChangeLogLockTableStatement());
109  executor.execute(new InitializeDatabaseChangeLogLockTableStatement());
110  }
111  }
112 
113  }
static final Logger log
Definition: CustomLockService.java:43

◆ releaseLock()

void org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockService.releaseLock ( )
inline
180  {
181  try {
182  if (hasChangeLogLock) {
183  log.debug("Going to release database lock");
184  database.commit();
185  } else {
186  log.warn("Attempt to release lock, which is not owned by current transaction");
187  }
188  } catch (Exception e) {
189  log.error("Database error during release lock", e);
190  } finally {
191  try {
192  hasChangeLogLock = false;
193  database.setCanCacheLiquibaseTableInfo(false);
194  database.rollback();
195  } catch (DatabaseException e) {
196  ;
197  }
198  }
199  }
static final Logger log
Definition: CustomLockService.java:43

◆ waitForLock()

void org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockService.waitForLock ( )
inline
116  {
117  boolean locked = false;
118  long startTime = Time.toMillis(Time.currentTime());
119  long timeToGiveUp = startTime + (getChangeLogLockWaitTime());
120  boolean nextAttempt = true;
121 
122  while (nextAttempt) {
123  locked = acquireLock();
124  if (!locked) {
125  int remainingTime = ((int)(timeToGiveUp / 1000)) - Time.currentTime();
126  if (remainingTime > 0) {
127  log.debugf("Will try to acquire log another time. Remaining time: %d seconds", remainingTime);
128  } else {
129  nextAttempt = false;
130  }
131  } else {
132  nextAttempt = false;
133  }
134  }
135 
136  if (!locked) {
137  int timeout = ((int)(getChangeLogLockWaitTime() / 1000));
138  throw new IllegalStateException("Could not acquire change log lock within specified timeout " + timeout + " seconds. Currently locked by other transaction");
139  }
140  }
boolean acquireLock()
Definition: CustomLockService.java:143
static final Logger log
Definition: CustomLockService.java:43

メンバ詳解

◆ log

final Logger org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockService.log = Logger.getLogger(CustomLockService.class)
staticprivate

このクラス詳解は次のファイルから抽出されました: