Exemplo n.º 1
0
  /**
   * write_state saves the ObjectState in a file named by the type and Uid of the ObjectState. If
   * the second argument is SHADOW, then the file name is different so that a subsequent
   * commit_state invocation will rename the file.
   *
   * <p>We need to make sure that each entry is written to the next empty location in the log even
   * if there's already an entry for this tx.
   */
  protected boolean write_state(Uid objUid, String tName, OutputObjectState state, int ft)
      throws ObjectStoreException {
    if (tsLogger.logger.isTraceEnabled()) {
      tsLogger.logger.trace(
          "ShadowingStore.write_state("
              + objUid
              + ", "
              + tName
              + ", "
              + StateType.stateTypeString(ft)
              + ")");
    }

    String fname = null;
    File fd = null;

    if (tName != null) {
      int imageSize = (int) state.length();
      byte[] uidString = objUid.stringForm().getBytes();
      int buffSize =
          _redzone.length
              + uidString.length
              + imageSize
              + 8; // don't put in endOfLog since we keep overwriting that.
      RandomAccessFile ofile = null;
      java.nio.channels.FileLock lock = null;

      if (imageSize > 0) {
        TransactionData theLogEntry =
            getLogName(objUid, tName, buffSize); // always adds entry to log
        LogInstance theLog = theLogEntry.container;

        if (theLog == null) throw new ObjectStoreException();

        fname = genPathName(theLog.getName(), tName, ft);
        fd = openAndLock(fname, FileLock.F_WRLCK, true);

        if (fd == null) {
          tsLogger.i18NLogger.warn_objectstore_ShadowingStore_18(fname);

          return false;
        }

        boolean setLength = !fd.exists();

        try {
          ofile = new RandomAccessFile(fd, FILE_MODE);

          if (setLength) {
            ofile.setLength(_maxFileSize);
          } else {
            // may have to resize file if we keep updating this transaction info

            if (theLog.remaining() < buffSize) {
              long size = ofile.length() + buffSize - theLog.remaining();

              ofile.setLength(size);

              theLog.resize(size);
            }
          }

          java.nio.ByteBuffer buff = java.nio.ByteBuffer.allocate(buffSize);

          buff.put(_redzone);
          buff.putInt(uidString.length);
          buff.put(uidString);
          buff.putInt(imageSize);
          buff.put(state.buffer());

          synchronized (_lock) {
            ofile.seek(theLogEntry.offset);

            ofile.write(buff.array());
          }
        } catch (SyncFailedException e) {
          unlockAndClose(fd, ofile);

          throw new ObjectStoreException(
              "ShadowingStore::write_state() - write failed to sync for " + fname, e);
        } catch (FileNotFoundException e) {
          unlockAndClose(fd, ofile);

          e.printStackTrace();

          throw new ObjectStoreException(
              "ShadowingStore::write_state() - write failed to locate file " + fname + ": " + e, e);
        } catch (IOException e) {
          unlockAndClose(fd, ofile);

          e.printStackTrace();

          throw new ObjectStoreException(
              "ShadowingStore::write_state() - write failed for " + fname + ": " + e, e);
        } finally {
          try {
            if (lock != null) lock.release();
          } catch (IOException ex) {
            ex.printStackTrace();
          }
        }
      }

      if (!unlockAndClose(fd, ofile)) {
        tsLogger.i18NLogger.warn_objectstore_ShadowingStore_19(fname);
      }

      super.addToCache(fname);

      return true;
    } else
      throw new ObjectStoreException(
          "ShadowStore::write_state - "
              + tsLogger.i18NLogger.get_objectstore_notypenameuid()
              + objUid);
  }
Exemplo n.º 2
0
  private final TransactionData getLogName(Uid txid, String tName, long size)
      throws ObjectStoreException {
    synchronized (_logNames) {
      Iterator<LogInstance> iter = _logNames.iterator();
      LogInstance entry = null;

      /*
       * First check to see if the TxId is in an existing log. Always
       * return the same log instance for the same txid so we can
       * keep all data in the same location. This may mean that we have
       * to extend the size of the log over time to accommodate situations
       * where the log is modified but not deleted for a while, e.g., during
       * recovery.
       */

      while (iter.hasNext()) {
        entry = (LogInstance) iter.next();

        if (entry.present(txid)) {
          if (size == -1) // we are reading only
          return entry.getTxId(txid);
          else return entry.addTxId(txid, size);
        }
      }

      /*
       * If we get here then this TxId isn't in one of the
       * logs we are maintaining currently. So go back through
       * the list of logs and find one that is small enough
       * for us to use. The first one with room will do.
       */

      iter = _logNames.iterator();

      while (iter.hasNext()) {
        entry = (LogInstance) iter.next();

        if (!entry.isFrozen()) {
          if (entry.remaining() > size) {
            return entry.addTxId(txid, size);
          } else {
            /*
             * TODO
             *
             * When can we remove the information about this
             * log from memory? If we do it too soon then it's possible
             * that delete entries will not go into the right log. If we
             * leave it too late then the memory footprint increases. Prune
             * the entry when we prune the log from disk?
             */

            entry.freeze();
          }
        }
      }

      // if we get here, then we need to create a new log

      entry = new LogInstance(tName, _maxFileSize);
      _logNames.add(entry);

      return entry.addTxId(txid, size);
    }
  }