Oracle 8i | Oracle 9i | Oracle 10g | Oracle 11g | Oracle 12c | Miscellaneous | PL/SQL | SQL | Oracle RAC | Oracle Apps | Linux

Oracle Database File System (DBFS) in Oracle Database 11g Release 2

Oracle has quite a long history with database file systems. The Oracle Internet File System (iFS) was released in the Oracle 8i days. This product was later renamed to Oracle Content Management SDK. The introduction of XML DB in Oracle 9i Release 2 brought with it a database file system accessible from HTTP, FTP and WebDAV for the storage of XML files. Now Oracle 11g Release 2 introduces DBFS, the Oracle Database File System.

DBFS creates a file system interface on top of database tables that store files as SecureFile LOBs. External access to the file system is via a client program (dbfs_client), which is only available for Linux and Solaris platforms. The client is already installed on the database server, but can also be installed on client machines, giving them access to the centralized database file system. On Linux platforms the dbfs_client can be used to mount the database file system on a regular mount point. This done using the "Filesystem in Userspace" (FUSE) project. This allows Linux machines to access DBFS like any other physical file system.

In this article I'll show the steps necessary to mount the DBFS on a Linux server. I'm not going to discuss the DBFS Content API, DBFS SecureFile Store or DBFS Hierarchical Store directly, although some of these are called by scripts used in this article.

Related articles.

Creating a File System

Create a tablespace to hold the file system.

CONN / AS SYSDBA

CREATE TABLESPACE dbfs_ts
  DATAFILE '/u01/app/oracle/oradata/DB11G/dbfs01.dbf'
  SIZE 1M AUTOEXTEND ON NEXT 1M;

Create a user, grant DBFS_ROLE to the user and make sure it has a quota on the tablespace. Trying to create a file system from the SYS user fails, so it must be done via another user.

CONN / AS SYSDBA

CREATE USER dbfs_user IDENTIFIED BY dbfs_user
  DEFAULT TABLESPACE dbfs_ts QUOTA UNLIMITED ON dbfs_ts;

GRANT CREATE SESSION, RESOURCE, CREATE VIEW, DBFS_ROLE TO dbfs_user;

Create the file system in tablespace by running the "dbfs_create_filesystem.sql" script as the test user. The script accepts two parameters identifying the tablespace and file system name.

cd $ORACLE_HOME/rdbms/admin
sqlplus dbfs_user/dbfs_user

SQL> @dbfs_create_filesystem.sql dbfs_ts staging_area

The script created a partitioned file system. Although Oracle consider this the best option from a performance and scalability perspective, it can have two drawbacks:

If these issues present a problem to you, you can create non-partitioned file systems using the "dbfs_create_filesystem_advanced.sql" script. In fact, the "dbfs_create_filesystem_advanced.sql" script is called by the "dbfs_create_filesystem.sql" script, which defaults many of the advanced parameters.

If we later wish to drop a file system, this can be done using the "dbfs_drop_filesystem.sql" script with the file system name.

cd $ORACLE_HOME/rdbms/admin
sqlplus dbfs_user/dbfs_user

SQL> @dbfs_drop_filesystem.sql staging_area

FUSE Installation

In order to mount the DBFS we need to install the "Filesystem in Userspace" (FUSE) software. If you are not planning to mount the DBFS or you are running on an Non-Linux platform, this section is unnecessary. The FUSE software can be installed manually, from the OEL media or via Oracle's public yum server. If possible, use the Yum installation.

Yum FUSE Installation

Configure the server to point to Oracle's public yum repository. The instructions for this are available at "http://public-yumn.oracle.com".

Next, install the kernel developent package. It may already be present, in which case you will see a "Nothing to do" message.

# yum install kernel-devel

Finally, install the FUSE software.

# yum install fuse fuse-libs

Media FUSE Installation

If you can't use the Yum installation method you can install FUSE from your OEL media.

First, check to see if the "kernel-devel" package is installed.

rpm -q kernel-devel
kernel-devel-2.6.18-128.el5
#

If not, then install it from your media.

# cd /media/cdrom/Server
# rpm -Uvh kernel-devel*

Then install the FUSE software from your media.

# cd /media/cdrom/Server
# rpm -Uvh fuse-2* fuse-libs-2*

Manual FUSE Installation

If you can't perform a Yum or media installation of FUSE, you can always install it manually. This assumes you have installed the kernel development package using one of the previous methods.

Download the FUSE 2.7.3 package from http://fuse.sourceforge.net/.

Determine the kernel directory.

# echo /usr/src/kernels/`uname -r`-`uname -p`
/usr/src/kernels/2.6.18-128.el5-x86_64
#

Install the FUSE package as the "root" user using the following commands, substituting your kernel directory.

# tar -xzvf fuse-2.7.3.tar.gz
# cd fuse-2.7.3
# ./configure --prefix=/usr --with-kernel=/usr/src/kernels/2.6.18-128.el5-x86_64
# make
# make install
# /sbin/depmod
# /sbin/modprobe fuse
# chmod 666 /dev/fuse
# echo "/sbin/modprobe fuse" >> /etc/rc.modules
# chmod 700 /etc/rc.modules

Mounting a File System

The dbfs_client tool is used to mount file systems on Linux servers. The usage is displayed if you call it without any parameters.

$ dbfs_client
usage: dbfs_client <db_user>@<db_server> [options] <mountpoint>
  db_user:              Name of Database user that owns DBFS content repository filesystem(s)
  db_server:            A valid connect string for Oracle database server
                        (for example, hrdb_host:1521/hrservice)
  mountpoint:           Path to mount Database File System(s)
                        All the file systems owned by the database user will be seen at the mountpoint.
DBFS options:
  -o direct_io          Bypass the Linux page cache. Gives much better performance for large files.
                        Programs in the file system cannot be executed with this option.
                        This option is recommended when DBFS is used as an ETL staging area.
  -o wallet             Run dbfs_client in background.
                        Wallet must be configured to get credentials.
  -o failover           dbfs_client fails over to surviving database instance with no data loss.
                        Some performance cost on writes, especially for small files.
  -o allow_root         Allows root access to the filesystem.
                        This option requires setting 'user_allow_other' parameter in '/etc/fuse.conf'.
  -o allow_other        Allows other users access to the file system.
                        This option requires setting 'user_allow_other' parameter in '/etc/fuse.conf'.
  -o rw                 Mount the filesystem read-write. [Default]
  -o ro                 Mount the filesystem read-only. Files cannot be modified.
  -o trace_file=STR     Tracing <filename> | 'syslog'
  -o trace_level=N      Trace Level: 1->DEBUG, 2->INFO, 3->WARNING, 4->ERROR, 5->CRITICAL [Default: 4]
  -h                    help
  -V                    version
[oracle@oel5-11gr2 admin]$

First we need to create a mount point with the necessary privileges as the "root" user.

# mkdir /mnt/dbfs
# chown oracle:oinstall /mnt/dbfs

Next, add a new library path.

# echo "/usr/local/lib" >> /etc/ld.so.conf.d/usr_local_lib.conf

Create symbolic links to the necessary libraries in the directory pointed to by the new library path. Note. Depending on your installation the "libfuse.so.2" library may be in an alternative location.

# export ORACLE_HOME=/u01/app/oracle/product/11.2.0/db_1
# ln -s $ORACLE_HOME/lib/libclntsh.so.11.1 /usr/local/lib/libclntsh.so.11.1
# ln -s $ORACLE_HOME/lib/libnnz11.so /usr/local/lib/libnnz11.so
# ln -s /lib64/libfuse.so.2 /usr/local/lib/libfuse.so.2

Issue the following command.

# ldconfig

The file system we've just created is mounted with the one of the following commands from the "oracle" OS user.

$ # Connection prompts for password and holds session.
$ dbfs_client dbfs_user@DB11G /mnt/dbfs

$ # Connection retrieves password from file and releases session.
$ nohup dbfs_client dbfs_user@DB11G /mnt/dbfs  < passwordfile.f &

$ # Connection authenticates using wallet and releases session.
$ nohup dbfs_client -o wallet /@DB11G_DBFS_USER /mnt/dbfs &

The wallet authentication is the safest method as the others potentially expose the credentials. Creation of a wallet is discussed later, but it is part of the Advanced Security option.

Once mounted, the "staging_area" file system is now available for use.

# ls -al /mnt/dbfs
total 8
drwxr-xr-x 3 root root    0 Jan  6 17:02 .
drwxr-xr-x 3 root root 4096 Jan  6 14:18 ..
drwxrwxrwx 3 root root    0 Jan  6 16:37 staging_area
# ls -al /mnt/dbfs/staging_area
total 0
drwxrwxrwx 3 root   root     0 Jan  6 16:37 .
drwxr-xr-x 3 root   root     0 Jan  6 17:02 ..
drwxr-xr-x 7 root   root     0 Jan  6 14:00 .sfs
#

To unmount the file system issue the following command from the "root" OS user.

# fusermount -u /mnt/dbfs

Wallet Creation

To create a wallet issue the following commands as the "oracle" OS user.

$ mkdir -p $HOME/oracle/wallet
$ $ORACLE_HOME/bin/mkstore -wrl $HOME/oracle/wallet -create

Add the following lines to the "$ORACLE_HOME/network/admin/sqlnet.ora" file.

WALLET_LOCATION = (SOURCE = (METHOD = FILE) (METHOD_DATA = (DIRECTORY = $HOME/oracle/wallet) ) ) 
SQLNET.WALLET_OVERRIDE = TRUE

Add the credentials to the wallet for a specific connect string. This could be the existing connect string (DB11G in mycase), but in this example I've used something a little more specific (DB11G_DBFS_USER).

$ mkstore -wrl $HOME/oracle/wallet -createCredential DB11G_DBFS_USER dbfs_user dbfs_user

Make sure the connect string is present in the "$ORACLE_HOME/network/admin/tnsnames.ora" file. In this case I just copied my existing connect string and gave it the new name.

DB11G_DBFS_USER =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = oel5-11gr2.localdomain)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = DB11G.WORLD)
    )
  )

The file system can now be mounted using the wallet.

$ nohup dbfs_client -o wallet /@DB11G_DBFS_USER /mnt/dbfs &

Using /etc/fstab

Apart from having a familiar syntax, the use of the "/etc/fstab" file for mounting seems a little pointless since FUSE does not support automount, so you will still have to manually mount the file systems after a reboot. Actually this is fortunate as the automount would probably happen before the database was up, which would of course would be an issue.

Note: When this article was first written, the documentation for this step was not complete and the method proposed by Oracle did not work. The documentation has since been altered, but unfortunately the latest proposed method seems to work only when mounted from the "root" user (not recommended), rather than the "oracle" user. As a result I have switched to using the method proposed by Frits Hoogland in the article here. It works fine from the "oracle" user, but it I can't get it to work with the Wallet. Personally, I prefer to use the mount commands listed in the Mounting a File System section.

To allow mount operations from the "/etc/fstab", issue the following commands as the "root" user.

# groupadd fuse
# usermod -a -G fuse oracle

Add the following line into the "/etc/fstab" file.

/sbin/mount.dbfs#dbfs_user@DB11G_DBFS_USER /mnt/dbfs fuse rw,user,noauto,direct_io 0 0

Create the "/sbin/mount.dbfs" file with the following contents.

#!/bin/bash
export ORACLE_HOME=/u01/app/oracle/product/11.2.0/db_1
nohup $ORACLE_HOME/bin/dbfs_client $@ << FEEDPWD &
dbfs_user
FEEDPWD

Set the permissions using the following commands.

# chmod 750 /sbin/mount.dbfs
# chgrp fuse /sbin/mount.dbfs

The filesystem should now be mounted using the following command from the "oracle" OS user.

$ mount /mnt/dbfs

As before, the filesystem is unmounted using the following command.

$ fusermount -u /mnt/dbfs

dbfs_client Command Interface

As only Linux clients will be able to mount the file system, the majority of clients will access the file system via the dbfs_client command line, which provides a variety of UNIX-like file system command using the following syntax.

dbfs_client <db_user>@<db_serverr> --command <command> [switches] [arguments]

Commands include some typical UNIX file system commands like ls, cp, rm, mkdir. Arguments are typically file or directory names. The available switches are -a (all files), -l (long format) and -R (recursive).

Paths within the DBFS are referenced using the "dbfs:/file-system-name/" prefix. If this is not present, the path is assumed to be on the local filesystem of the machine running the client software.

Here are some examples of commands using the dbfs_client with the file system and wallet created earlier.

$ # Directory listing.
$ dbfs_client /@DB11G_DBFS_USER --command ls -a -l dbfs:/staging_area/
drwxr-xr-x              root            root               0    Jan 06 19:32    .sfs
$

$ # Make a directory and get directory listing.
$ dbfs_client /@DB11G_DBFS_USER --command mkdir dbfs:/staging_area/test_dir
$
$ dbfs_client /@DB11G_DBFS_USER --command ls -a -l dbfs:/staging_area/
drwx------            oracle        oinstall               0    Jan 07 11:41    dbfs:/staging_area/test_dir
drwxr-xr-x              root            root               0    Jan 06 19:32    .sfs
$

$ # Copy files to and from DBFS
$ dbfs_client /@DB11G_DBFS_USER --command cp /tmp/test.txt dbfs:/staging_area/test_dir/
/tmp/test.txt -> dbfs:/staging_area/test_dir/test.txt
$
$ dbfs_client /@DB11G_DBFS_USER --command cp dbfs:/staging_area/test_dir/test.txt /tmp/test_copy.txt 
dbfs:/staging_area/test_dir/test.txt -> /tmp/test_copy.txt
$

$ # Remove file
$ dbfs_client /@DB11G_DBFS_USER --command rm dbfs:/staging_area/test_dir/test.txt
Unlinking file dbfs:/staging_area/test_dir/test.txt
$

The command list is quite limited at the moment, but the message returned from unsupported commands suggests more are on their way.

$ dbfs_client /@DB11G_DBFS_USER --command rmdir dbfs:/staging_area/test_dir
rmdir is not supported right now
$

Switches must applied separately (-a -l), not grouped (-al) or the results are unpredictable. Also, wildcards do not work.

For more information see:

Hope this helps. Regards Tim...

Back to the Top.