Home » hive-0.5.0-dev » org.apache.hadoop.hive.ql.util.jdbm.recman » [javadoc | source]

    1   /**
    2    * Licensed to the Apache Software Foundation (ASF) under one
    3    * or more contributor license agreements.  See the NOTICE file
    4    * distributed with this work for additional information
    5    * regarding copyright ownership.  The ASF licenses this file
    6    * to you under the Apache License, Version 2.0 (the
    7    * "License"); you may not use this file except in compliance
    8    * with the License.  You may obtain a copy of the License at
    9    *
   10    *     http://www.apache.org/licenses/LICENSE-2.0
   11    *
   12    * Unless required by applicable law or agreed to in writing, software
   13    * distributed under the License is distributed on an "AS IS" BASIS,
   14    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15    * See the License for the specific language governing permissions and
   16    * limitations under the License.
   17    */
   18   
   19   /**
   20    * JDBM LICENSE v1.00
   21    *
   22    * Redistribution and use of this software and associated documentation
   23    * ("Software"), with or without modification, are permitted provided
   24    * that the following conditions are met:
   25    *
   26    * 1. Redistributions of source code must retain copyright
   27    *    statements and notices.  Redistributions must also contain a
   28    *    copy of this document.
   29    *
   30    * 2. Redistributions in binary form must reproduce the
   31    *    above copyright notice, this list of conditions and the
   32    *    following disclaimer in the documentation and/or other
   33    *    materials provided with the distribution.
   34    *
   35    * 3. The name "JDBM" must not be used to endorse or promote
   36    *    products derived from this Software without prior written
   37    *    permission of Cees de Groot.  For written permission,
   38    *    please contact cg@cdegroot.com.
   39    *
   40    * 4. Products derived from this Software may not be called "JDBM"
   41    *    nor may "JDBM" appear in their names without prior written
   42    *    permission of Cees de Groot.
   43    *
   44    * 5. Due credit should be given to the JDBM Project
   45    *    (http://jdbm.sourceforge.net/).
   46    *
   47    * THIS SOFTWARE IS PROVIDED BY THE JDBM PROJECT AND CONTRIBUTORS
   48    * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
   49    * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   50    * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
   51    * CEES DE GROOT OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
   52    * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   53    * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   54    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   55    * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   56    * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   57    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   58    * OF THE POSSIBILITY OF SUCH DAMAGE.
   59    *
   60    * Copyright 2000 (C) Cees de Groot. All Rights Reserved.
   61    * Copyright 2000-2001 (C) Alex Boisvert. All Rights Reserved.
   62    * Contributions are Copyright (C) 2000 by their associated contributors.
   63    *
   64    * $Id: BaseRecordManager.java,v 1.8 2005/06/25 23:12:32 doomdark Exp $
   65    */
   66   
   67   package org.apache.hadoop.hive.ql.util.jdbm.recman;
   68   
   69   import java.io.IOException;
   70   import java.io.File;
   71   
   72   import java.util.HashMap;
   73   import java.util.Map;
   74   
   75   import org.apache.hadoop.hive.ql.util.jdbm.RecordManager;
   76   import org.apache.hadoop.hive.ql.util.jdbm.helper.Serializer;
   77   import org.apache.hadoop.hive.ql.util.jdbm.helper.DefaultSerializer;
   78   
   79   /**
   80    *  This class manages records, which are uninterpreted blobs of data. The
   81    *  set of operations is simple and straightforward: you communicate with
   82    *  the class using long "rowids" and byte[] data blocks. Rowids are returned
   83    *  on inserts and you can stash them away someplace safe to be able to get
   84    *  back to them. Data blocks can be as long as you wish, and may have
   85    *  lengths different from the original when updating.
   86    *  <p>
   87    *  Operations are synchronized, so that only one of them will happen
   88    *  concurrently even if you hammer away from multiple threads. Operations
   89    *  are made atomic by keeping a transaction log which is recovered after
   90    *  a crash, so the operations specified by this interface all have ACID
   91    *  properties.
   92    *  <p>
   93    *  You identify a file by just the name. The package attaches <tt>.db</tt>
   94    *  for the database file, and <tt>.lg</tt> for the transaction log. The
   95    *  transaction log is synchronized regularly and then restarted, so don't
   96    *  worry if you see the size going up and down.
   97    *
   98    * @author <a href="mailto:boisvert@intalio.com">Alex Boisvert</a>
   99    * @author <a href="cg@cdegroot.com">Cees de Groot</a>
  100    * @version $Id: BaseRecordManager.java,v 1.8 2005/06/25 23:12:32 doomdark Exp $
  101    */
  102   public final class BaseRecordManager
  103       implements RecordManager
  104   {
  105   
  106       /**
  107        * Underlying record file.
  108        */
  109       private RecordFile _file;
  110   
  111   
  112       /**
  113        * Physical row identifier manager.
  114        */
  115       private PhysicalRowIdManager _physMgr;
  116   
  117   
  118       /**
  119        * Logigal to Physical row identifier manager.
  120        */
  121       private LogicalRowIdManager _logMgr;
  122   
  123   
  124       /**
  125        * Page manager.
  126        */
  127       private PageManager _pageman;
  128   
  129   
  130       /**
  131        * Reserved slot for name directory.
  132        */
  133       public static final int NAME_DIRECTORY_ROOT = 0;
  134   
  135   
  136       /**
  137        * Static debugging flag
  138        */
  139       public static final boolean DEBUG = false;
  140   
  141       
  142       /**
  143        * Directory of named JDBMHashtables.  This directory is a persistent
  144        * directory, stored as a Hashtable.  It can be retrived by using
  145        * the NAME_DIRECTORY_ROOT.
  146        */
  147       private Map _nameDirectory;
  148   
  149   
  150       /**
  151        *  Creates a record manager for the indicated file
  152        *
  153        *  @throws IOException when the file cannot be opened or is not
  154        *          a valid file content-wise.
  155        */
  156       public BaseRecordManager( String filename )
  157           throws IOException
  158       {
  159           _file = new RecordFile( filename );
  160           _pageman = new PageManager( _file );
  161           _physMgr = new PhysicalRowIdManager( _file, _pageman );
  162           _logMgr = new LogicalRowIdManager( _file, _pageman );
  163       }
  164       
  165        /**
  166        *  Creates a record manager for the indicated file
  167        *
  168        *  @throws IOException when the file cannot be opened or is not
  169        *          a valid file content-wise.
  170        */
  171       public BaseRecordManager( File file )
  172           throws IOException
  173       {
  174           _file = new RecordFile( file );
  175           _pageman = new PageManager( _file );
  176           _physMgr = new PhysicalRowIdManager( _file, _pageman );
  177           _logMgr = new LogicalRowIdManager( _file, _pageman );
  178       }
  179       
  180       
  181   
  182   
  183       /**
  184        *  Get the underlying Transaction Manager
  185        */
  186       public synchronized TransactionManager getTransactionManager()
  187       {
  188           checkIfClosed();
  189   
  190           return _file.txnMgr;
  191       }
  192   
  193   
  194       /**
  195        *  Switches off transactioning for the record manager. This means
  196        *  that a) a transaction log is not kept, and b) writes aren't
  197        *  synch'ed after every update. This is useful when batch inserting
  198        *  into a new database.
  199        *  <p>
  200        *  Only call this method directly after opening the file, otherwise
  201        *  the results will be undefined.
  202        */
  203       public synchronized void disableTransactions()
  204       {
  205           checkIfClosed();
  206   
  207           _file.disableTransactions();
  208       }
  209   
  210       
  211       /**
  212        *  Closes the record manager.
  213        *
  214        *  @throws IOException when one of the underlying I/O operations fails.
  215        */
  216       public synchronized void close()
  217           throws IOException
  218       {
  219           checkIfClosed();
  220   
  221           _pageman.close();
  222           _pageman = null;
  223   
  224           _file.close();
  225           _file = null;
  226       }
  227   
  228   
  229       /**
  230        *  Inserts a new record using standard java object serialization.
  231        *
  232        *  @param obj the object for the new record.
  233        *  @return the rowid for the new record.
  234        *  @throws IOException when one of the underlying I/O operations fails.
  235        */
  236       public long insert( Object obj )
  237           throws IOException
  238       {
  239           return insert( obj, DefaultSerializer.INSTANCE );
  240       }
  241   
  242       
  243       /**
  244        *  Inserts a new record using a custom serializer.
  245        *
  246        *  @param obj the object for the new record.
  247        *  @param serializer a custom serializer
  248        *  @return the rowid for the new record.
  249        *  @throws IOException when one of the underlying I/O operations fails.
  250        */
  251       public synchronized long insert( Object obj, Serializer serializer )
  252           throws IOException
  253       {
  254           byte[]    data;
  255           long      recid;
  256           Location  physRowId;
  257           
  258           checkIfClosed();
  259   
  260           data = serializer.serialize( obj );
  261           physRowId = _physMgr.insert( data, 0, data.length );
  262           recid = _logMgr.insert( physRowId ).toLong();
  263           if ( DEBUG ) {
  264               System.out.println( "BaseRecordManager.insert() recid " + recid + " length " + data.length ) ;
  265           }
  266           return recid;
  267       }
  268   
  269       /**
  270        *  Deletes a record.
  271        *
  272        *  @param recid the rowid for the record that should be deleted.
  273        *  @throws IOException when one of the underlying I/O operations fails.
  274        */
  275       public synchronized void delete( long recid )
  276           throws IOException
  277       {
  278           checkIfClosed();
  279           if ( recid <= 0 ) {
  280               throw new IllegalArgumentException( "Argument 'recid' is invalid: "
  281                                                   + recid );
  282           }
  283   
  284           if ( DEBUG ) {
  285               System.out.println( "BaseRecordManager.delete() recid " + recid ) ;
  286           }
  287   
  288           Location logRowId = new Location( recid );
  289           Location physRowId = _logMgr.fetch( logRowId );
  290           _physMgr.delete( physRowId );
  291           _logMgr.delete( logRowId );
  292       }
  293   
  294   
  295       /**
  296        *  Updates a record using standard java object serialization.
  297        *
  298        *  @param recid the recid for the record that is to be updated.
  299        *  @param obj the new object for the record.
  300        *  @throws IOException when one of the underlying I/O operations fails.
  301        */
  302       public void update( long recid, Object obj )
  303           throws IOException
  304       {
  305           update( recid, obj, DefaultSerializer.INSTANCE );
  306       }
  307   
  308       
  309       /**
  310        *  Updates a record using a custom serializer.
  311        *
  312        *  @param recid the recid for the record that is to be updated.
  313        *  @param obj the new object for the record.
  314        *  @param serializer a custom serializer
  315        *  @throws IOException when one of the underlying I/O operations fails.
  316        */
  317       public synchronized void update( long recid, Object obj, Serializer serializer )
  318           throws IOException
  319       {
  320           checkIfClosed();
  321           if ( recid <= 0 ) {
  322               throw new IllegalArgumentException( "Argument 'recid' is invalid: "
  323                                                   + recid );
  324           }
  325   
  326           Location logRecid = new Location( recid );
  327           Location physRecid = _logMgr.fetch( logRecid );
  328           
  329           byte[] data = serializer.serialize( obj );
  330           if ( DEBUG ) {
  331               System.out.println( "BaseRecordManager.update() recid " + recid + " length " + data.length ) ;
  332           }
  333           
  334           Location newRecid = _physMgr.update( physRecid, data, 0, data.length );
  335           if ( ! newRecid.equals( physRecid ) ) {
  336               _logMgr.update( logRecid, newRecid );
  337           }
  338       }
  339   
  340   
  341       /**
  342        *  Fetches a record using standard java object serialization.
  343        *
  344        *  @param recid the recid for the record that must be fetched.
  345        *  @return the object contained in the record.
  346        *  @throws IOException when one of the underlying I/O operations fails.
  347        */
  348       public Object fetch( long recid )
  349           throws IOException
  350       {
  351           return fetch( recid, DefaultSerializer.INSTANCE );
  352       }
  353   
  354   
  355       /**
  356        *  Fetches a record using a custom serializer.
  357        *
  358        *  @param recid the recid for the record that must be fetched.
  359        *  @param serializer a custom serializer
  360        *  @return the object contained in the record.
  361        *  @throws IOException when one of the underlying I/O operations fails.
  362        */
  363       public synchronized Object fetch( long recid, Serializer serializer )
  364           throws IOException
  365       {
  366           byte[] data;
  367   
  368           checkIfClosed();
  369           if ( recid <= 0 ) {
  370               throw new IllegalArgumentException( "Argument 'recid' is invalid: "
  371                                                   + recid );
  372           }
  373           data = _physMgr.fetch( _logMgr.fetch( new Location( recid ) ) );
  374           if ( DEBUG ) {
  375               System.out.println( "BaseRecordManager.fetch() recid " + recid + " length " + data.length ) ;
  376           }
  377           return serializer.deserialize( data );
  378       }
  379   
  380   
  381       /**
  382        *  Returns the number of slots available for "root" rowids. These slots
  383        *  can be used to store special rowids, like rowids that point to
  384        *  other rowids. Root rowids are useful for bootstrapping access to
  385        *  a set of data.
  386        */
  387       public int getRootCount()
  388       {
  389           return FileHeader.NROOTS;
  390       }
  391   
  392       /**
  393        *  Returns the indicated root rowid.
  394        *
  395        *  @see #getRootCount
  396        */
  397       public synchronized long getRoot( int id )
  398           throws IOException
  399       {
  400           checkIfClosed();
  401   
  402           return _pageman.getFileHeader().getRoot( id );
  403       }
  404   
  405   
  406       /**
  407        *  Sets the indicated root rowid.
  408        *
  409        *  @see #getRootCount
  410        */
  411       public synchronized void setRoot( int id, long rowid )
  412           throws IOException
  413       {
  414           checkIfClosed();
  415   
  416           _pageman.getFileHeader().setRoot( id, rowid );
  417       }
  418   
  419   
  420       /**
  421        * Obtain the record id of a named object. Returns 0 if named object
  422        * doesn't exist.
  423        */
  424       public long getNamedObject( String name )
  425           throws IOException
  426       {
  427           checkIfClosed();
  428   
  429           Map nameDirectory = getNameDirectory();
  430           Long recid = (Long) nameDirectory.get( name );
  431           if ( recid == null ) {
  432               return 0;
  433           }
  434           return recid.longValue();
  435       }
  436   
  437       /**
  438        * Set the record id of a named object.
  439        */
  440       public void setNamedObject( String name, long recid )
  441           throws IOException
  442       {
  443           checkIfClosed();
  444   
  445           Map nameDirectory = getNameDirectory();
  446           if ( recid == 0 ) {
  447               // remove from hashtable
  448               nameDirectory.remove( name );
  449           } else {
  450               nameDirectory.put( name, new Long( recid ) );
  451           }
  452           saveNameDirectory( nameDirectory );
  453       }
  454   
  455   
  456       /**
  457        * Commit (make persistent) all changes since beginning of transaction.
  458        */
  459       public synchronized void commit()
  460           throws IOException
  461       {
  462           checkIfClosed();
  463   
  464           _pageman.commit();
  465       }
  466   
  467   
  468       /**
  469        * Rollback (cancel) all changes since beginning of transaction.
  470        */
  471       public synchronized void rollback()
  472           throws IOException
  473       {
  474           checkIfClosed();
  475   
  476           _pageman.rollback();
  477       }
  478   
  479   
  480       /**
  481        * Load name directory
  482        */
  483       private Map getNameDirectory()
  484           throws IOException
  485       {
  486           // retrieve directory of named hashtable
  487           long nameDirectory_recid = getRoot( NAME_DIRECTORY_ROOT );
  488           if ( nameDirectory_recid == 0 ) {
  489               _nameDirectory = new HashMap();
  490               nameDirectory_recid = insert( _nameDirectory );
  491               setRoot( NAME_DIRECTORY_ROOT, nameDirectory_recid );
  492           } else {
  493               _nameDirectory = (Map) fetch( nameDirectory_recid );
  494           }
  495           return _nameDirectory;
  496       }
  497   
  498   
  499       private void saveNameDirectory( Map directory )
  500           throws IOException
  501       {
  502           long recid = getRoot( NAME_DIRECTORY_ROOT );
  503           if ( recid == 0 ) {
  504               throw new IOException( "Name directory must exist" );
  505           }
  506           update( recid, _nameDirectory );
  507       }
  508   
  509   
  510       /**
  511        * Check if RecordManager has been closed.  If so, throw an
  512        * IllegalStateException.
  513        */
  514       private void checkIfClosed()
  515           throws IllegalStateException
  516       {
  517           if ( _file == null ) {
  518               throw new IllegalStateException( "RecordManager has been closed" );
  519           }
  520       }
  521   }

Home » hive-0.5.0-dev » org.apache.hadoop.hive.ql.util.jdbm.recman » [javadoc | source]