Package com.aelitis.azureus.core.diskmanager.file.impl

Source Code of com.aelitis.azureus.core.diskmanager.file.impl.FMFileAccessController

/*
* Created on 30-Nov-2005
* Created by Paul Gardner
* Copyright (C) 2005, 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
* AELITIS, SAS au capital de 40,000 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/

package com.aelitis.azureus.core.diskmanager.file.impl;

import java.io.File;
import java.io.RandomAccessFile;

import org.gudy.azureus2.core3.torrent.TOTorrent;
import org.gudy.azureus2.core3.torrent.TOTorrentFile;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.DirectByteBuffer;
import org.gudy.azureus2.core3.util.DirectByteBufferPool;
import org.gudy.azureus2.core3.util.StringInterner;

import com.aelitis.azureus.core.diskmanager.file.FMFile;
import com.aelitis.azureus.core.diskmanager.file.FMFileManagerException;

public class
FMFileAccessController
  implements FMFileAccess
{
  private static final String REORDER_SUFFIX = ".2";

  private static final boolean TEST_PIECE_REORDER = System.getProperty( "azureus.file.piece.reorder.force", "0" ).equals( "1" );
 
  static{
    if ( TEST_PIECE_REORDER ){
     
      Debug.out( "*** Piece reordering storage forced ***" );
    }
  }
  private FMFileImpl  owner;
 
  private int    type    = FMFile.FT_LINEAR;
 
  private File  control_dir;
  private String  controlFileName;
 
  private FMFileAccess  file_access;
   
  protected
  FMFileAccessController(
    FMFileImpl  _file,
    int      _target_type )
 
    throws FMFileManagerException
  {
    if ( TEST_PIECE_REORDER ){
 
      _target_type = FMFile.FT_PIECE_REORDER;
    }
   
    owner    = _file;
   
    // actual file shouldn't exist for change to occur - it is the responsibility
    // of the caller to delete the file first and take consequent actions (in
    // particular force recheck the file to ensure that the loss in save state
    // is represented in the resume view of the world )

    // in the future, if we support format conversion, this obviously changes
 
    setControlFile();
 
    if ( control_dir == null ){
     
      // Debug.out( "No control file" ); in optimised environments we don't support compact and return null here
     
      if ( _target_type == FMFile.FT_LINEAR ){
       
        file_access = new FMFileAccessLinear( owner );
       
      }else{
       
        throw( new FMFileManagerException( "Compact storage not supported: no control file available" ));
      }

    }else{
   
      if ( new File( control_dir, controlFileName ).exists()){
       
        type = FMFile.FT_COMPACT;
       
      }else if ( new File( control_dir, controlFileName + REORDER_SUFFIX ).exists()){
     
        type = _target_type==FMFile.FT_PIECE_REORDER?FMFile.FT_PIECE_REORDER:FMFile.FT_PIECE_REORDER_COMPACT;
       
      }else{
       
        if ((_target_type == FMFile.FT_PIECE_REORDER || _target_type == FMFile.FT_PIECE_REORDER_COMPACT )){
         
          File  target_file = owner.getLinkedFile();
         
          if ( target_file.exists()){
         
            FMFileAccessPieceReorderer.recoverConfig(
              owner.getOwner().getTorrentFile(),
              target_file,
              new File( control_dir, controlFileName + REORDER_SUFFIX ));
          }
         
          type = _target_type;
         
        }else{
         
          type = FMFile.FT_LINEAR;
        }
      }
           
      if ( type == FMFile.FT_LINEAR ){
       
        file_access = new FMFileAccessLinear( owner );
       
      }else if ( type == FMFile.FT_COMPACT ){
       
        file_access =
          new FMFileAccessCompact(
              owner.getOwner().getTorrentFile(),
              control_dir,
              controlFileName, 
              new FMFileAccessLinear( owner ));
      }else{
       
        file_access =
          new FMFileAccessPieceReorderer(
              owner.getOwner().getTorrentFile(),
              control_dir,
              controlFileName + REORDER_SUFFIX, 
              new FMFileAccessLinear( owner ));
      }
             
      convert( _target_type );
    }
  }
 
  protected void
  convert(
    int          target_type )
 
    throws FMFileManagerException
 
    if ( type == target_type ){
     
      return;
    }
   
    if ( type == FMFile.FT_PIECE_REORDER || target_type == FMFile.FT_PIECE_REORDER ){
     
      if ( target_type == FMFile.FT_PIECE_REORDER_COMPACT || type == FMFile.FT_PIECE_REORDER_COMPACT ){
       
          // these two access modes are in fact identical at the moment
       
        type = target_type;
       
        return;
      }
     
      throw( new FMFileManagerException( "Conversion to/from piece-reorder not supported" ));
    }
   
    File  file = owner.getLinkedFile();
     
    RandomAccessFile raf = null;
   
    boolean  ok  = false;
   
    try{
      FMFileAccess  target_access;
     
      if ( target_type == FMFile.FT_LINEAR ){
       
        target_access = new FMFileAccessLinear( owner );
                 
      }else{
       
        target_access = new FMFileAccessCompact(
                    owner.getOwner().getTorrentFile(),control_dir,
                    controlFileName, 
                    new FMFileAccessLinear( owner ));
      }

      if ( file.exists()){

        raf = new RandomAccessFile( file, FMFileImpl.WRITE_ACCESS_MODE);
       
          // due to the simplistic implementation of compact we only actually need to deal with
          // the last piece of the file (first piece is in the right place already)
       
        FMFileAccessCompact  compact_access;
       
        if ( target_type == FMFile.FT_LINEAR ){
                   
          compact_access = (FMFileAccessCompact)file_access;
           
        }else{
         
           compact_access = (FMFileAccessCompact)target_access;
        }
       
        long  length = file_access.getLength( raf );
       
        long  last_piece_start   = compact_access.getLastPieceStart();
        long  last_piece_length   = compact_access.getLastPieceLength();
       
          // see if we have any potential data for the last piece
       
        if ( last_piece_length > 0 && length > last_piece_start ){
         
          long  data_length = length - last_piece_start;
         
          if ( data_length > last_piece_length ){
           
            Debug.out("data length inconsistent: len=" + data_length + ",limit=" + last_piece_length );
           
            data_length = last_piece_length;
          }
         
          DirectByteBuffer  buffer =
            DirectByteBufferPool.getBuffer( DirectByteBuffer.AL_FILE, (int)data_length );
         
          try{
         
            file_access.read( raf, new DirectByteBuffer[]{ buffer }, last_piece_start );
           
              // see if we need to truncate
           
            if ( target_type == FMFile.FT_COMPACT ){
             
              long  first_piece_length = compact_access.getFirstPieceLength();
             
              long  physical_length = raf.length();
             
              if ( physical_length > first_piece_length ){
           
                raf.setLength( first_piece_length );
              }
            }
           
            buffer.flip( DirectByteBuffer.AL_FILE );
           
            target_access.write( raf, new DirectByteBuffer[]{ buffer }, last_piece_start );
           
          }finally{
           
            buffer.returnToPool();
          }
        }else{
         
            // no last piece, truncate after the first piece
         
          if ( target_type == FMFile.FT_COMPACT ){
           
            long  first_piece_length = compact_access.getFirstPieceLength();
           
            long  physical_length = raf.length();
           
            if ( physical_length > first_piece_length ){
         
              raf.setLength( first_piece_length );
            }
          }
        }
         
        target_access.setLength( raf, length );
       
        target_access.flush();
      }
     
      type    = target_type;
      file_access  = target_access;
 
      ok  = true;
     
    }catch( Throwable e ){
     
      Debug.printStackTrace( e );
     
      throw( new FMFileManagerException( "convert fails", e ));
     
    }finally{
     
      try{
        if ( raf != null ){
         
          try{
            raf.close();
           
          }catch( Throwable e ){
         
              // override original exception if there isn't one
           
            if ( ok ){
             
              ok  = false;
             
              throw( new FMFileManagerException( "convert fails", e ));
            }
          }
        }
      }finally{
       
        if ( !ok ){
                 
            // conversion failed - replace with linear access, caller is responsible for
            // handling this (marking file requiring recheck)
         
          type    = FMFile.FT_LINEAR; 
          file_access = new FMFileAccessLinear( owner );
        }
       
        if ( type == FMFile.FT_LINEAR ){
         
          new File(control_dir,controlFileName).delete()
        }
      }
    }
  }
 
  protected void
  setControlFile()
  {
    TOTorrentFile  tf = owner.getOwner().getTorrentFile();
   
    if ( tf == null ){

      controlFileName = null;
      control_dir = null;
    }
   
    TOTorrent  torrent = tf.getTorrent();
   
    TOTorrentFile[]  files = torrent.getFiles();
   
    int  file_index = -1;
   
    for (int i=0;i<files.length;i++){
     
      if ( files[i] == tf ){
   
        file_index = i;
       
        break;
      }
    }
   
    if ( file_index == -1 ){
     
      Debug.out("File '" + owner.getName() + "' not found in torrent!" );
     
      controlFileName = null;
      control_dir   = null;
     
    }else{
     
      control_dir   = owner.getOwner().getControlFileDir( );
      controlFileName =  StringInterner.intern("fmfile" + file_index + ".dat");
    }
  }
 
 
  public void
  setStorageType(
    int          new_type )
 
    throws FMFileManagerException
  {   
    convert( new_type );
  }
 
  public int
  getStorageType()
  {
    return( type );
  }
 
 
    // FileAccess
 
  public void
  aboutToOpen()
 
    throws FMFileManagerException
  {
    file_access.aboutToOpen();
  }
 
  public long
  getLength(
    RandomAccessFile    raf )
 
    throws FMFileManagerException
  {
    return( file_access.getLength( raf ));
  }
 
  public void
  setLength(
    RandomAccessFile    raf,
    long          length )
 
    throws FMFileManagerException
  {
    file_access.setLength( raf, length );
  }
 
  public boolean
  isPieceCompleteProcessingNeeded(
    int          piece_number )
  {
    return( file_access.isPieceCompleteProcessingNeeded( piece_number ));
  }
 
  public void
  setPieceComplete(
    RandomAccessFile  raf,
    int          piece_number,
    DirectByteBuffer  piece_data )
 
    throws FMFileManagerException
  {
    file_access.setPieceComplete( raf, piece_number, piece_data );
  }
 
  public void
  read(
    RandomAccessFile  raf,
    DirectByteBuffer[]  buffers,
    long        offset )
 
    throws FMFileManagerException
  {
    file_access.read( raf, buffers, offset );
  }
 
  public void
  write(
    RandomAccessFile    raf,
    DirectByteBuffer[]    buffers,
    long          position )
 
    throws FMFileManagerException
  {
    file_access.write( raf, buffers, position );
  }
 
  public void
  flush()
 
    throws FMFileManagerException
  {
    file_access.flush();
  }
 
  public FMFileImpl
  getFile()
  {
    return( owner );
  }
 
  public String
  getString()
  {
    return( "type=" + type + ",acc=" + file_access.getString());
  }
}
TOP

Related Classes of com.aelitis.azureus.core.diskmanager.file.impl.FMFileAccessController

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.