All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.tentackle.dbms.PooledDb Maven / Gradle / Ivy

/*
 * Tentackle - https://tentackle.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.tentackle.dbms;

import org.tentackle.common.Constants;
import org.tentackle.common.Timestamp;
import org.tentackle.log.Logger;
import org.tentackle.session.PersistenceException;
import org.tentackle.session.SessionFactory;

import java.lang.ref.WeakReference;

/**
 * Session managed by the session pool.
 */
public class PooledDb {

  private static final Logger LOGGER = Logger.get(PooledDb.class);

  private final DbPool pool;                // the session pool
  private final int slotNumber;             // the slot number
  private Db db;                            // the managed db, null if currently lent
  private final String dbStr;               // the db string (not the reference!)
  private final WeakReference refDb;    // weak reference to detect unreferenced lent Db instances
  private long usedSince;                   // last lend time, 0 if in pool
  private String usingThreadStr;            // the lending thread string (not the reference!), null if in pool
  private String mdcStr;                    // mapped diagnostic context string
  private long unusedSince;                 // last return time, 0 if lent
  private long firstUse;                    // epochal time of first use


  /**
   * Creates a pooled session.
   *
   * @param pool the session pool
   * @param slotNumber the slot number within the pool
   */
  public PooledDb(DbPool pool, int slotNumber) {
    this.pool = pool;
    this.slotNumber = slotNumber;

    db = createSession(slotNumber);
    db.setPool(pool);
    dbStr = db.toString();
    unusedSince = System.currentTimeMillis();
    refDb = new WeakReference<>(db);
  }

  /**
   * Gets the session pool.
   *
   * @return the pool
   */
  public DbPool getPool() {
    return pool;
  }

  /**
   * Gets the slot number.
   *
   * @return the slot number
   */
  public int getSlotNumber() {
    return slotNumber;
  }

  /**
   * Returns the managed session.
   *
   * @return the managed session, null if currently lent
   */
  public Db getSession() {
    return db;
  }

  /**
   * Gets the referenced session.
* This is the value of a {@link WeakReference}. * * @return the session, null if no more referenced. */ public Db getReferencedDb() { return refDb.get(); } /** * Get epochal time of first use. * * @return the epochal time */ public long getFirstUse() { return firstUse; } /** * Gets the time lent. * * @return the epochal time since in use, 0 if not lent */ public long getUsedSince() { return usedSince; } /** * Gets the last return time. * * @return the epochal time last returned, 0 if lent */ public long getUnusedSince() { return unusedSince; } /** * Gets the lending thread string.
* Avoids the references to the thread. * * @return the thread name, null if in pool */ public String getUsingThreadStr() { return usingThreadStr; } /** * Gets the mapped diagnostic context string. * * @return the MDC */ public String getMdcStr() { return mdcStr; } @Override public String toString() { return pool + "#" + slotNumber + "|" + dbStr; } /** * Closes a pooled db. */ public void close() { Db dbToClose = refDb.get(); // db may be null because currently lent if (dbToClose != null) { // refDb.db may be null because already garbage collected try { dbToClose.close(); } catch (RuntimeException rex) { LOGGER.warning("closing pooled Db " + dbToClose + " failed", rex); } finally { db = null; } } } /** * Marks a pooled db used. * * @param usingThread the using thread */ public void use(Thread usingThread) { if (db == null) { throw new PersistenceException("unexpected loss of reference to " + dbStr + " (last returned by " + usingThreadStr + " since " + new Timestamp(unusedSince) + ")"); } usedSince = System.currentTimeMillis(); if (firstUse == 0) { firstUse = usedSince; } unusedSince = 0; usingThreadStr = usingThread.toString(); mdcStr = LOGGER.getMappedDiagnosticContext().toString(); // keep only the weak reference db = null; } /** * Marks a pooled db unused. */ public void unUse(Db db) { // switch back to hard reference this.db = refDb.get(); if (this.db == null) { throw new PersistenceException("unexpected loss of reference to " + dbStr + " (last use by " + usingThreadStr + " since " + new Timestamp(usedSince) + ")"); } if (this.db != db) { this.db = null; throw new PersistenceException("attempt to un-use " + db + " in wrong slot " + dbStr + " (last use by " + usingThreadStr + " since " + new Timestamp(usedSince) + ")"); } unusedSince = System.currentTimeMillis(); usedSince = 0; usingThreadStr = null; mdcStr = null; } /** * Checks for forgotten puts. * * @return true if db has been lent but never returned and is not referenced anymore */ public boolean isUnreferenced() { return refDb.get() == null; } /** * Returns the number of minutes the session has been unused. * * @param currentTimeMillis the current time to refer to in epochal milliseconds * @return the idle minutes, 0 if in use or never used at all */ public long idleMinutes(long currentTimeMillis) { return firstUse == 0 || unusedSince == 0 ? 0 : (currentTimeMillis - unusedSince) / Constants.MINUTE_MS; } /** * Returns the number of minutes the session has been used at all. * * @param currentTimeMillis the current time to refer to in epochal milliseconds * @return the usage minutes, 0 if never used at all */ public long usedMinutes(long currentTimeMillis) { return firstUse == 0 ? 0 : (currentTimeMillis - firstUse) / Constants.MINUTE_MS; } /** * Creates a new session. * * @param slotNumber the slot number * @return the open session */ protected Db createSession(int slotNumber) { LOGGER.fine("open pooled Db for {0}, connection manager {1}, slot {2}", pool.getSessionInfo(), pool.getConnectionManager(), slotNumber); Db session = (Db) SessionFactory.getInstance().create(pool, pool.createSessionInfo(slotNumber)); if (pool.getSessionGroupId() != 0) { session.groupWith(pool.getSessionGroupId()); } return session; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy