Package org.apache.directory.server.core.partition.impl.btree.jdbm

Source Code of org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition

/*
*  Licensed to the Apache Software Foundation (ASF) under one
*  or more contributor license agreements.  See the NOTICE file
*  distributed with this work for additional information
*  regarding copyright ownership.  The ASF licenses this file
*  to you under the Apache License, Version 2.0 (the
*  "License"); you may not use this file except in compliance
*  with the License.  You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing,
*  software distributed under the License is distributed on an
*  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
*  KIND, either express or implied.  See the License for the
*  specific language governing permissions and limitations
*  under the License.
*
*/
package org.apache.directory.server.core.partition.impl.btree.jdbm;


import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import jdbm.RecordManager;
import jdbm.helper.MRU;
import jdbm.recman.BaseRecordManager;
import jdbm.recman.CacheRecordManager;

import org.apache.directory.server.constants.ApacheSchemaConstants;
import org.apache.directory.server.core.partition.Partition;
import org.apache.directory.server.core.partition.impl.btree.AbstractBTreePartition;
import org.apache.directory.server.i18n.I18n;
import org.apache.directory.server.xdbm.Index;
import org.apache.directory.server.xdbm.search.impl.CursorBuilder;
import org.apache.directory.server.xdbm.search.impl.DefaultOptimizer;
import org.apache.directory.server.xdbm.search.impl.DefaultSearchEngine;
import org.apache.directory.server.xdbm.search.impl.EvaluatorBuilder;
import org.apache.directory.server.xdbm.search.impl.NoOpOptimizer;
import org.apache.directory.shared.ldap.model.cursor.Cursor;
import org.apache.directory.shared.ldap.model.cursor.Tuple;
import org.apache.directory.shared.ldap.model.entry.Attribute;
import org.apache.directory.shared.ldap.model.entry.Entry;
import org.apache.directory.shared.ldap.model.entry.Value;
import org.apache.directory.shared.ldap.model.schema.AttributeType;
import org.apache.directory.shared.ldap.model.schema.SchemaManager;
import org.apache.directory.shared.util.exception.MultiException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
* A {@link Partition} that stores entries in
* <a href="http://jdbm.sourceforge.net/">JDBM</a> database.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class JdbmPartition extends AbstractBTreePartition<Long>
{
    /** static logger */
    private static final Logger LOG = LoggerFactory.getLogger( JdbmPartition.class );

    private static final String JDBM_DB_FILE_EXTN = ".db";
   
    private static final FilenameFilter DB_FILTER = new FilenameFilter()
    {
       
        public boolean accept( File dir, String name )
        {
            // really important to filter master.db and master.lg files
            return ( name.endsWith( JDBM_DB_FILE_EXTN ) && !name.startsWith( "master." ) );
        }
    };

    /** the JDBM record manager used by this database */
    private RecordManager recMan;

    /**
     * Creates a store based on JDBM B+Trees.
     */
    public JdbmPartition( SchemaManager schemaManager )
    {
        super( schemaManager );

        // Initialize the cache size
        if ( cacheSize < 0 )
        {
            cacheSize = DEFAULT_CACHE_SIZE;
            LOG.debug( "Using the default entry cache size of {} for {} partition", cacheSize, id );
        }
        else
        {
            LOG.debug( "Using the custom configured cache size of {} for {} partition", cacheSize, id );
        }
    }


    protected void doInit() throws Exception
    {
        if ( !initialized )
        {
            // setup optimizer and registries for parent
            if ( !optimizerEnabled )
            {
                optimizer = new NoOpOptimizer();
            }
            else
            {
                optimizer = new DefaultOptimizer<Entry, Long>( this );
            }
   
            EvaluatorBuilder<Long> evaluatorBuilder = new EvaluatorBuilder<Long>( this, schemaManager );
            CursorBuilder<Long> cursorBuilder = new CursorBuilder<Long>( this, evaluatorBuilder );
   
            searchEngine = new DefaultSearchEngine<Long>( this, cursorBuilder, evaluatorBuilder, optimizer );

            // Create the underlying directories (only if needed)
            File partitionDir = new File( getPartitionPath() );
            partitionDir.mkdirs();
   
            // Initialize the indexes
            super.doInit();
   
            // First, check if the file storing the data exists
            String path = partitionDir.getPath() + File.separator + "master";
            BaseRecordManager baseRecordManager = new BaseRecordManager( path );
            baseRecordManager.disableTransactions();
   
            if ( cacheSize < 0 )
            {
                cacheSize = DEFAULT_CACHE_SIZE;
                LOG.debug( "Using the default entry cache size of {} for {} partition", cacheSize, id );
            }
            else
            {
                LOG.debug( "Using the custom configured cache size of {} for {} partition", cacheSize, id );
            }
   
            // Now, create the entry cache for this partition
            recMan = new CacheRecordManager( baseRecordManager, new MRU( cacheSize ) );
   
            // Create the master table (the table containing all the entries)
            master = new JdbmMasterTable<Entry>( recMan, schemaManager );
   
            // get all index db files first
            File[] allIndexDbFiles = partitionDir.listFiles( DB_FILTER );
           
            // get the names of the db files also
            List<String> indexDbFileNameList = Arrays.asList( partitionDir.list( DB_FILTER ) );
   
            // then add all index objects to a list
            List<String> allIndices = new ArrayList<String>();
           
            for( Index<?, Entry, Long> index : systemIndices.values() )
            {
                allIndices.add( index.getAttribute().getOid() );
            }
   
            // this loop is used for two purposes
            // one for collecting all user indices
            // two for finding a new index to be built
            // just to avoid another iteration for determining which is the new index
            for( Index<?, Entry, Long> index : userIndices.values() )
            {
                allIndices.add( index.getAttributeId() );
   
                // take the part after removing .db from the 
                String name = index.getAttributeId() + JDBM_DB_FILE_EXTN;
   
                // if the name doesn't exist in the list of index DB files
                // this is a new index and we need to build it
                if ( !indexDbFileNameList.contains( name ) )
                {
                    buildUserIndex( index );
                }
            }
   
            deleteUnusedIndexFiles( allIndices, allIndexDbFiles );
           
            // We are done !
            initialized = true;
        }
    }

   
    /**
     * {@inheritDoc}}
     */
    public Long getDefaultId()
    {
        return 1L;
    }


    /**
     * {@inheritDoc}
     */
    public Long getRootId()
    {
        return 0L;
    }


    /**
     * This method is called when the synch thread is waking up, to write
     * the modified data.
     *
     * @throws Exception on failures to sync database files to disk
     */
    public synchronized void sync() throws Exception
    {
        if ( !initialized )
        {
            return;
        }

        // Sync all system indices
        for ( Index<?, Entry, Long> idx : systemIndices.values() )
        {
            idx.sync();
        }
       
        // Sync all user defined userIndices
        for ( Index<?, Entry, Long> idx : userIndices.values() )
        {
            idx.sync();
        }

        ( ( JdbmMasterTable<Entry> ) master ).sync();
        recMan.commit();
    }
   
   
    /**
     * builds a user defined index on a attribute by browsing all the entries present in master db
     *
     * @param userIdx then user defined index
     * @throws Exception in case of any problems while building the index
     */
    private void buildUserIndex( Index userIdx ) throws Exception
    {
        AttributeType atType = userIdx.getAttribute();

        LOG.info( "building the index for attribute type {}", atType );
       
        Cursor<Tuple<Long,Entry>> cursor = master.cursor();
        cursor.beforeFirst();
       
        String attributeOid = userIdx.getAttribute().getOid();
       
        while ( cursor.next() )
        {
            Tuple<Long,Entry> tuple = cursor.get();
           
            Long id = tuple.getKey();
            Entry entry = tuple.getValue();
           
            Attribute entryAttr = entry.get( atType );
           
            if ( entryAttr != null )
            {
                for ( Value<?> value : entryAttr )
                {
                    userIdx.add( value.getValue(), id );
                }
               
                // Adds only those attributes that are indexed
                presenceIdx.add( attributeOid, id );
            }
        }
       
        cursor.close();
    }
    /**
     * removes any unused/removed attribute index files present under the partition's
     * working directory
     */
    private void deleteUnusedIndexFiles( List<String> allIndices, File[] dbFiles )
    {
        for ( File file : dbFiles )
        {
            String name = file.getName();
            // take the part after removing .db from the 
            name = name.substring( 0, name.lastIndexOf( JDBM_DB_FILE_EXTN ) );
           
            // remove the file if not found in the list of names of indices
            if( !allIndices.contains( name ) )
            {
                boolean deleted = file.delete();
               
                if( deleted )
                {
                    LOG.info( "Deleted unused index file {}", file.getAbsolutePath() );

                    try
                    {
                        String atName = schemaManager.lookupAttributeTypeRegistry( name ).getName();
                        File txtFile = new File( file.getParent(), name + "-" + atName + ".txt" );
                       
                        deleted = txtFile.delete();
                       
                        if( !deleted )
                        {
                            LOG.info( "couldn't delete the index name helper file {}", txtFile );
                        }
                    }
                    catch( Exception e )
                    {
                        LOG.warn( "couldn't find the attribute's name with oid {}", name );
                        LOG.warn( "", e );
                    }
                }
                else
                {
                    LOG.warn( "Failed to delete unused index file {}", file.getAbsolutePath() );
                }
            }
        }
    }
   
   
    /**
     * {@inheritDoc}
     */
    protected Index<?, Entry, Long> convertAndInit( Index<?, Entry, Long> index ) throws Exception
    {
        JdbmIndex<?, Entry> jdbmIndex;
       
        if ( index.getAttributeId().equals( ApacheSchemaConstants.APACHE_RDN_AT_OID ) )
        {
            jdbmIndex = new JdbmRdnIndex();
            jdbmIndex.setAttributeId( ApacheSchemaConstants.APACHE_RDN_AT_OID );
            jdbmIndex.setCacheSize( index.getCacheSize() );
            jdbmIndex.setNumDupLimit( JdbmIndex.DEFAULT_DUPLICATE_LIMIT );
            jdbmIndex.setWkDirPath( index.getWkDirPath() );
        }
        else if ( index instanceof JdbmIndex<?, ?> )
        {
            jdbmIndex = ( JdbmIndex<?, Entry> ) index;
           
            if ( jdbmIndex.getWkDirPath() == null )
            {
                jdbmIndex.setWkDirPath( partitionPath );
            }
        }
        else
        {
            LOG.debug( "Supplied index {} is not a JdbmIndex.  "
                + "Will create new JdbmIndex using copied configuration parameters.", index );
            jdbmIndex = new JdbmIndex( index.getAttributeId() );
            jdbmIndex.setCacheSize( index.getCacheSize() );
            jdbmIndex.setNumDupLimit( JdbmIndex.DEFAULT_DUPLICATE_LIMIT );
            jdbmIndex.setWkDirPath( index.getWkDirPath() );
        }

        jdbmIndex.init( schemaManager, schemaManager.lookupAttributeTypeRegistry( index.getAttributeId() ) );

        return jdbmIndex;
    }


    /**
     * {@inheritDoc}
     */
    protected synchronized void doDestroy() throws Exception
    {
        MultiException errors = new MultiException( I18n.err( I18n.ERR_577 ) );

        if ( !initialized )
        {
            return;
        }
       
        try
        {
            super.doDestroy();
        }
        catch ( Exception e )
        {
            errors.addThrowable( e );
        }

        // This is specific to the JDBM store : close the record manager
        try
        {
            recMan.close();
            LOG.debug( "Closed record manager for {} partition.", suffixDn );
        }
        catch ( Throwable t )
        {
            LOG.error( I18n.err( I18n.ERR_127 ), t );
            errors.addThrowable( t );
        }

        if ( errors.size() > 0 )
        {
            throw errors;
        }
    }
}
TOP

Related Classes of org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition

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.