1 22 package com.lutris.appserver.server.sql.standard; 23 24 import java.math.BigDecimal ; 25 import java.math.BigInteger ; 26 import java.sql.PreparedStatement ; 27 import java.sql.ResultSet ; 28 import java.sql.SQLException ; 29 30 import org.enhydra.dods.DODS; 31 32 import com.lutris.appserver.server.sql.DBConnection; 33 import com.lutris.appserver.server.sql.DatabaseManagerException; 34 import com.lutris.appserver.server.sql.LogicalDatabase; 35 import com.lutris.appserver.server.sql.ObjectId; 36 import com.lutris.appserver.server.sql.ObjectIdAllocationError; 37 import com.lutris.appserver.server.sql.ObjectIdAllocator; 38 import com.lutris.appserver.server.sql.ObjectIdException; 39 import com.lutris.logging.Logger; 40 import com.lutris.util.Config; 41 import com.lutris.util.ConfigException; 42 import com.lutris.util.KeywordValueException; 43 44 71 public class StandardObjectIdAllocator implements ObjectIdAllocator { 72 73 76 private ObjectId max = null; 77 78 81 private ObjectId current = null; 82 83 86 private ObjectId next = null; 87 88 94 private long cacheSize = 1024; 95 96 100 private boolean columnWithPrefix = false; 101 102 103 106 private String oidTableName = "objectid"; 107 108 111 private String nextColumnName = "next"; 112 116 private String oidMinValue = "0"; 117 118 122 private LogicalDatabase logicalDatabase = null; 123 124 125 129 private String primaryLogicalDatabaseName = null; 130 131 138 private static final int LOG_THRESHOLD = 100; 139 140 141 149 protected StandardObjectIdAllocator(LogicalDatabase lDb, Config objIdConfig) 150 throws ConfigException { 151 try { 152 primaryLogicalDatabaseName = objIdConfig.getString("PrimaryLogicalDatabase", lDb.getName()); 153 cacheSize = objIdConfig.getInt("CacheSize", 1024); 154 oidMinValue = objIdConfig.getString("MinValue", "10000000000000000"); 155 columnWithPrefix = objIdConfig.getBoolean("NextWithPrefix",false); 156 oidTableName = objIdConfig.getString("OidTableName","objectid"); 157 nextColumnName = objIdConfig.getString("NextColumnName","next"); 158 } catch (KeywordValueException except) { 159 throw new ConfigException("Bad DatabaseManager.DB." 160 + primaryLogicalDatabaseName 161 + ".ObjectId section defined in config file."); 162 } 163 } 164 165 173 public synchronized void checkOId(ObjectId oid) throws ObjectIdException { 174 if (oid == null) { 175 throw new ObjectIdException("Object id is null"); 176 } 177 BigDecimal min = new BigDecimal (new BigInteger (oidMinValue)); 178 BigDecimal id = new BigDecimal (oid.toString()); 179 180 if (id.compareTo(min) == -1) { 181 throw new ObjectIdException("Object id out of range"); 182 } 183 if (next == null || max == null) { 184 updateCache(); 185 } 186 BigDecimal bdNext = new BigDecimal (next.toString()); 187 188 if (id.compareTo(bdNext) == 0 || id.compareTo(bdNext) == 1) { 189 throw new ObjectIdException("Object id out of range"); 190 } 191 } 192 193 196 public synchronized ObjectId allocate() { 197 try { 198 if (next == null || max == null || next.equals(max)) { 199 updateCache(); 200 } 201 current = next; next = next.increment(); 203 return current; 204 } catch (Exception e) { 205 throw new ObjectIdAllocationError("ObjectIdAllocator: " 206 + "\nFailed to allocate object id. Caused by: " + "\n" 207 + e.getMessage()); 208 } 209 } 210 211 216 private void updateCache() { 217 final String OID_TABLE = oidTableName; 218 DBConnection conn = null; 219 220 try { 221 boolean tryAgain = false; 222 int tryCount = 0; 223 224 conn = allocateConnection(); 225 conn.setAutoCommit(false); 226 do { 227 BigDecimal dbNext; 228 ResultSet rs; 229 230 rs = conn.executeQuery("select * from " + OID_TABLE); 232 if (!rs.next()) { 233 conn.executeUpdate("insert into " + OID_TABLE + " values(" 235 + oidMinValue + ")"); 236 dbNext = new BigDecimal (oidMinValue); 237 } else { 238 dbNext = rs.getBigDecimal(nextColumnName); 239 } 240 rs.close(); next = new ObjectId(dbNext); 243 BigDecimal dbLast = dbNext; 246 247 dbNext = dbNext.add(BigDecimal.valueOf(cacheSize)); 248 String sql = "update " + OID_TABLE + " "; if(!columnWithPrefix) 253 sql+= "set " +nextColumnName +" = ?" + " " + "where "+nextColumnName +"= ?"; 254 else 255 sql+= "set " + OID_TABLE + "."+nextColumnName+" = ?" + " " + "where " + OID_TABLE + "."+nextColumnName+" = ?"; 256 PreparedStatement stmt = conn.prepareStatement(sql); 260 261 stmt.setBigDecimal(1, dbNext); 262 stmt.setBigDecimal(2, dbLast); 266 if (conn.executeUpdate(stmt, sql) < 1) { 270 tryAgain = true; 272 tryCount++; 273 if (tryCount >= LOG_THRESHOLD) { 274 DODS.getLogChannel().write(Logger.EMERGENCY, 275 "ObjectIdAllocator: " 276 + "\n Failed to allocate object ids." 277 + "\n Trying again...."); 278 } 279 conn.rollback(); 281 conn.reset(); conn.setAutoCommit(false); 283 if (tryCount >= 50) { 284 DODS.getLogChannel().write(Logger.EMERGENCY, 285 "ObjectIdAllocator: " 286 + "\n Failed to allocate object ids." 287 + "\n Tried 50 times. Giving up."); 288 throw new ObjectIdAllocationError("Failed to allocate object id." 289 + "\nTried 50 times. Giving up."); 290 } 291 } else { 292 tryAgain = false; 293 max = new ObjectId(dbNext); 295 conn.commit(); 297 if (tryCount >= LOG_THRESHOLD) { 298 DODS.getLogChannel().write(Logger.EMERGENCY, 299 "ObjectIdAllocator: " 300 + "\n Succeeded in allocating object ids." 301 + "\n Continuing..."); 302 } 303 } 304 } while (tryAgain); 305 } catch (SQLException sqlExcept) { 306 max = next; DODS.getLogChannel().write(Logger.EMERGENCY, 309 "ObjectIdAllocator: " 310 + "\n Failed to allocate object ids. Giving up!" 311 + "\n SQLState = " + sqlExcept.getSQLState() 312 + "\n SQLError = " + sqlExcept.getErrorCode() 313 + "\n SQLMsg = " + sqlExcept.getMessage()); 314 if (conn != null) { 315 try { 316 conn.rollback(); 317 } catch (SQLException rollbackExcept) { 318 DODS.getLogChannel().write(Logger.EMERGENCY, 319 "ObjectIdAllocator: " 320 + "\n Failed to rollback transaction." 321 + "\n SQLState = " + rollbackExcept.getSQLState() 322 + "\n SQLError = " 323 + rollbackExcept.getErrorCode() 324 + "\n SQLMsg = " + rollbackExcept.getMessage()); 325 } 326 if (!conn.handleException(sqlExcept)) { 327 conn = null; 328 } 329 } 330 throw new ObjectIdAllocationError("ObjectIdAllocator: " 331 + "\n Failed to allocate object id. Caused by SQLException:" 332 + "\n SQLState = " + sqlExcept.getSQLState() 333 + "\n SQLError = " + sqlExcept.getErrorCode() 334 + "\n SQLMsg = " + sqlExcept.getMessage()); 335 } catch (ObjectIdException oidEx) { 336 throw new ObjectIdAllocationError("ObjectIdAllocator: " 337 + "\nFailed to allocate object id. Caused by: " + "\n" 338 + oidEx.getMessage()); 339 } 340 finally { 341 if (conn != null) { 342 try { 343 conn.reset(); } catch (SQLException sqlExcept) { 345 DODS.getLogChannel().write(Logger.EMERGENCY, 346 "ObjectIdAllocator: " 347 + "\n Failed to reset connection." 348 + "\n SQLState = " + sqlExcept.getSQLState() 349 + "\n SQLError = " + sqlExcept.getErrorCode() 350 + "\n SQLMsg = " + sqlExcept.getMessage()); 351 } 352 finally { 353 conn.release(); 354 } 355 } 356 } 357 } 358 359 private DBConnection allocateConnection() throws SQLException { 360 if (logicalDatabase == null) { 361 try { 362 logicalDatabase = DODS.getDatabaseManager().findLogicalDatabase(primaryLogicalDatabaseName); 363 } catch (DatabaseManagerException e) { 364 e.printStackTrace(); 365 throw new SQLException (e.getMessage()); 366 } 367 } 368 return logicalDatabase.allocateConnection(); 369 } 370 } 371 | Popular Tags |