
#include "bacula_template.inc" title="Bacula Catalog Services"


<h1>Catalog Services</h1>

<h2>General</h2>
This chapter is intended to be a technical discussion of the
Catalog services and as such is not targeted at end users but
rather at developers and system administrators that want or
need to know more of the working details of <b>Bacula</b>.

<p>The <b>Bacula Catalog</b> services consist of the programs that  
provide the SQL database engine for storage and retrieval
of all information concerning files that were backed up and
their locations on the storage media.

<p>We have investigated the possibility of using the following SQL
engines for Bacula: Beagle, mSQL, GNU SQL, PostgreSQL, and MySQL. Each
presents certain problems with either licensing or maturity.  At
present, we have chosen for development purposes to use MySQL and
SQLite.  MySQL was chosen because it is fast, proven to be reliable,
widely used, and actively being developed.  In addition, the current
version of MySQL is released under the GNU GPL license.  SQLite was
chosen because it is small, efficient, and can be directly embedded in
<b>Bacula</b> thus requiring much less effort from the system
administrator or person building
<b>Bacula</b>. In our testing SQLite has performed very well,
and for the functions that we use, it has never encountered
any errors. Our experience using SQLite is, however, somewhat
limited at this time (24 March 2002) compared to MySQL.

<p>The <b>Bacula</b> SQL code has been written in a manner
that will allow it to be easily modified to support any
of the current SQL database systems on the market (for example:
PostgreSQL, mSQL, iODBC, unixODBC, Solid, OpenLink ODBC, 
EasySoft ODBC, InterBase, Oracle8, Oracle7, and DB2).
  
<p>If you do not specify either <b>--with-mysql</b> or 
<b>--with-sqlite</b>
on the ./configure line, <b>Bacula</b> will use
its minimalist internal database. This is not
recommended except for some developers.
At the current time,
this internal database supports most of the features
needed by Bacula (job records, pool records, media
records, ...). However, it does not currently keep
track of the filenames saved for each job nor
permit any SQL command. In addition, there is no
means for doing a <b>retention</b> command on the
internal database (i.e. no way to trim the growing
size of the database).</p>

<h3>Filenames and Maximum Filename Length</h3>
On Kern's Linux RedHat 7.1 development system, there are
approximately 90,000 files, of which 149 have a filename
length (including full path) greater than 100 characters.
The maximum filename length found on this system is 133 bytes.
<p>
In general, either MySQL or SQLite permit storing arbitrary long path
names and file names in the catalog database.  In practice, there are
still one or two places in the Catalog interface code that restrict the
maximum path length to 512 characters and the maximum file name length
to 512 characters.  These restrictions will be removed in the next major
release. Please note, these restrictions apply only to the Catalog
database and thus to your ability to list online the files
saved during any job. All information received and stored by the
Storage daemon (normally on tape) allows and handles arbitrarily
long path and filenames.

<h3>Installing and Configuring MySQL</h3>
For the details of installing and configuring MySQL,
please see the <a href="mysql.html">Installing and Configuring MySQL</a>
chapter of this manual.

<h3>Installing and Configuring SQLite</h3>
For the details of installing and configuring SQLite,
please see the <a href="sqlite.html">Installing and Configuring SQLite</a>
chapter of this manual.

<h3>Internal Bacula Catalog</h3>
Please see the <a href="internaldb.html">Internal Bacula Database</a>
chapter of this manual for more details.

<h3>Database Table Design</h3>
All discussions that follow pertain to the MySQL database.
The details for the SQLite database are essentially identical
except for that all fields in the SQLite database are stored
as ASCII text and some of the database creation statements
are a bit different.
The details of the internal Bacula catalog are not discussed
here.
<p>
Because the Catalog database may contain very large amounts of
data for large sites, we have made a modest attempt to normalize
the data tables to reduce redundant information. While reducing 
the size of the database significantly, it does, unfortunately,
add some complications to the structures.

<p>In simple terms, the Catalog database must contain a record
of all Jobs run by Bacula, and for each Job, it must maintain
a list of all files saved, with their File Attributes (permissions,
create date, ...), and the location and Media on which the file
is stored. This is seemingly a simple task, but it represents
a huge amount interlinked data. Note: the list of files and
their attributes is not maintained when using the internal
Bacula database. The data stored in the File records, which
allows the user or administrator to obtain a list of all
files backed up during a job, is by far the largest volume
of information put into the Catalog database.
<p>Although the Catalog database has been designed to handle
backup data for multiple clients, some users may want to
maintain multiple databases, one for each machine to be
backed up. This reduces the risk of confusion of accidental 
restoring a file to the wrong machine as well as reducing the
amount of data in a single database, thus increasing efficiency
and reducing the impact of a lost or damaged database.

<h2>Sequence of Creation of Records for a Save Job</h2>
Start with StartDate, ClientName, Filename, Path, Attributes,
MediaName, MediaCoordinates. (PartNumber, NumParts). In the
steps below, &quot;Create new&quot; means to create a new
record whether or not it is unique. &quot;Create unique&quot;
means each record in the database should be unique. Thus,
one must first search to see if the record exists, and only
if not should a new one be created, otherwise the existing
RecordId should be used.
<ol type="1">
    <li>Create new Job record with StartDate; save JobId</li>
    <li>Create unique Media record; save MediaId</li>
    <li>Create unique Client record; save ClientId</li>
    <li>Create unique Filename record; save FilenameId</li>
    <li>Create unique Path record; save PathId</li>
    <li>Create unique Attribute record; save AttributeId
       <br>store ClientId, FilenameId, PathId, and Attributes</li>
    <li>Create new File record
       <br>store JobId, AttributeId, MediaCoordinates, etc</li>
    <li>Repeat steps 4 through 8 for each file</li>
    <li>Create a JobMedia record; save MediaId</li>
    <li>Update Job record filling in EndDate and other Job statistics</li>
</ol>

<h2>Database Tables</h2>

<!--  Filename Table -->
<table cellspacing="2" cellpadding="2" border="3">
<tr> <th colspan="3" align=left>Filename</th> </tr>
<tr> <th>Column Name</th>  <th align="left">Data Type</th> <th align="left">Remark</th> </tr>
<tr> <td>FilenameId</td>  <td>integer</td>   <td>Primary Key</td> </tr>
<tr> <td>Name</td>        <td>Blob</td>      <td align=left>Filename</td>  </tr>
</table>
<p>The <b>Filename</b> table shown above contains the name of each file
backed up with the path removed.  If different directories or machines
contain the same filename, only one copy will be saved in this table.
<p>&nbsp;<p>

<!--  Path Table -->
<table cellspacing="2" cellpadding="2" border="3">
<tr> <th colspan="3" align="left">Path</th> </tr>
<tr> <th>Column Name</th> <th>Data Type</th>    <th>Remark</th> </tr>
<tr> <td>PathId</td>      <td>integer</td>      <td align=left>Primary Key</td> </tr>
<tr> <td>Path</td>        <td>Blob</td> <td align=left>Full Path</td>  </tr>
</table>
<p>The <b>Path</b> table contains shown above the path or directory
names of all directories on the system or systems.  The filename and any
MSDOS disk name are stripped off.  As with the filename, only one copy
of each directory name is kept regardless of how many machines or drives
have the same directory.  These path names should be stored in Unix path
name format.

<p>Some simple testing on a Linux file system indicates that separating
the filename and the path may be more complication than is warranted
by the space savings. For example, this system has a total of 89,097 files,
60,467 of which have unique filenames, and there are 4,374 unique paths.
<p>Finding all those files and doing two stats() per
file takes an average wall clock time of 1 min 35 seconds
on a 400MHz machine running RedHat 6.1 Linux.

<p>Finding all those files and putting them directly into a MySQL
database with the path and filename defined as TEXT,
which is variable length up to 65,535 characters takes
19 mins 31 seconds and creates a 27.6 MByte database.

<p>Doing the same thing, but inserting them into Blob
fields with the filename indexed on the first 30 characters
and the path name indexed on the 255 (max) characters takes
5 mins 18 seconds and creates a 5.24 MB database.  Rerunning
the job (with the database already created) takes about
2 mins 50 seconds.

<p>Running the same as the last one (Path and Filename
Blob), but Filename indexed on the first 30 characters
and the Path on the first 50 characters (linear search done there
after) takes 5 mins on the average and creates a 3.4 MB database.
Rerunning with the data already in the DB takes 3 mins 35 seconds.
<p>Finally, saving only the full path name rather than splitting
the path and the file, and indexing it on the first 50 characters
takes 6 mins 43 seconds and creates a 7.35 MB database.
<p></p>
<p>&nbsp;<p></p>

<!--   File Table -->
<table cellspacing="2" cellpadding="2" border="3">
<tr> <th colspan="3" align=left>File</th> </tr>
<tr> <th>Column Name</th>    <th>Data Type</th> <th align=center>Remark</th> </tr>
<tr>  <td>FileId</td>         <td>bigint</td>    <td>Primary Key</td> </tr>
<tr> <td>FileIndex</td>      <td>integer</td>   <td>The sequential file number in the Job</td> </tr>
<tr> <td>JobId</td>          <td>integer</td>   <td>Link to Job Record</td></tr>
<tr> <td>PathId</td>         <td>integer</td>   <td>Link to Path Record</td></tr>
<tr> <td>FilenameId</td>     <td>integer</td>   <td>Link to Filename Record</td></tr>
<tr> <td>MarkId</td>         <td>integer</td>   <td>Used to mark files during Verify Jobs</td></tr>
<tr> <td>LStat</td>          <td>tinyblob</td>  <td>File attributes in base64 encoding</td>  </tr>
<tr> <td>MD5</td>            <td>tinyblob</td>  <td>MD5 signature in base64 encoding</td>  </tr>
</table>
<p>The <b>File</b> table shown above contains one entry for each file
backed up by Bacula.  Thus a file that is backed up multiple times (as
is normal) will have multiple entries in the File table.  This will
probably be the table with the most number of records.  Consequently, it
is essential to keep the size of this record to an absolute minimum.  At
the same time, this table must contain all the information (or pointers
to the information) about the file and where it is backed up.  Since a
file may be backed up many times without having changed, the path and
filename are stored in separate tables.
<p>This table contains by far the largest amount of information in 
the Catalog database, both from the stand point of number of records,
and the stand point of total database size. As a consequence, 
the user must take care to periodically reduce the number of File
records using the <b>retention</b> command in the Console program.
<p>&nbsp;<p>

<!--    Job Table  -->
<table cellspacing="2" cellpadding="2" border="3">
<tr> <th colspan="3" align="left">Job</th> </tr>
<tr> <th>Column Name</th>    <th>Data Type</th> <th>Remark</th> </tr>
<tr> <td>JobId</td>          <td>integer</td>   <td>Primary Key</td> </tr>
<tr> <td>Job</td>            <td>tinyblob</td>  <td>Unique Job Name </td>  </tr>
<tr> <td>Name</td>           <td>tinyblob</td>  <td>Job Name </td>  </tr>
<tr> <td>PurgedFiles</td>    <td>tinyint</td>   <td>Used by Bacula for purging/retention periods</td></tr>
<tr> <td>Type</td>           <td>char</td>      <td>Job Type: Backup, Copy, Clone, Archive, Migration</td></tr>
<tr> <td>Level</td>          <td>char</td>      <td>Job Level</td></tr>
<tr> <td>ClientId</td>       <td>integer</td>   <td>Client index</td></tr>
<tr> <td>JobStatus</td>      <td>char</td>      <td>Job Termination Status</td></tr>
<tr> <td>SchedTime</td>      <td>datetime</td>  <td>Time/date when Job scheduled</td>  </tr>
<tr> <td>StartTime</td>      <td>datetime</td>  <td>Time/date when Job started</td>  </tr>
<tr> <td>EndTime</td>        <td>datetime</td>  <td>Time/date when Job ended</td>  </tr>
<tr> <td>JobTDate</td>       <td>bigint</td>   <td>Start day in Unix format but 64 bits; 
                                                   used for Retention period.</td></tr>
<tr> <td>VolSessionId</td>   <td>integer</td>   <td>Unique Volume Session ID</td>  </tr>
<tr> <td>VolSessionTime</td> <td>integer</td>   <td>Unique Volume Session Time</td>  </tr>
<tr> <td>JobFiles</td>       <td>integer</td>   <td>Number of files saved in Job</td>  </tr>
<tr> <td>JobBytes</td>       <td>bigint</td>   <td>Number of bytes saved in Job</td>  </tr>
<tr> <td>JobErrors</td>      <td>integer</td>   <td>Number of errors during Job</td>  </tr>
<tr> <td>JobMissingFiles</td> <td>integer</td>  <td>Number of files not saved (not yet used)</td>  </tr>
<tr> <td>PoolId</td>         <td>integer</td>   <td>Link to Pool Record</td>  </tr>
<tr> <td>FileSetId</td>      <td>integer</td>   <td>Link to FileSet Record</td>  </tr>
</table>
<p>The <b>Job</b> table contains one record for each Job run by Bacula. Thus
normally, there will be one per day per machine added to the database.
Note, the JobId is used to index Job records in the database, and it
often is shown to the user in the Console program. However, care must be
taken with its use as it is not unique from database to database. For example,
the user may have a database for Client data saved on machine Rufus and
another database for Client data saved on machine Roxie. In this case,
the two database will each have JobIds that match those in another
database. For a unique reference to a Job, see Job below.
<p>The Name field of the Job record corresponds to the Name resource
record given in the Director's configuration file. Thus it is a generic
name, and it will be normal to find many Jobs (or even all Jobs) with
the same Name.
<p>The Job field contains a combination of the Name and the schedule 
time of the Job by the Director. Thus for a given Director, even
with multiple Catalog databases, the Job will contain a unique name that
represents the Job.
<p>For a given Storage daemon, the VolSessionId and VolSessionTime
form a unique identification of the Job. This will be the case
even if multiple Directors are using the same Storage daemon.
<p>&nbsp;<p>


<!--   FileSet Table -->
<table cellspacing="2" cellpadding="2" border="3">
<tr> <th colspan="3" align="left">FileSet</th> </tr>
<tr> <th>Column Name</th>    <th>Data Type&nbsp;&nbsp;&nbsp;</th>    <th>Remark</th> </tr>
<tr> <td>FileSetId</td>      <td>integer</td>      <td>Primary Key</td> </tr>
<tr> <td>FileSet</td>        <td>tinyblob</td>   <td>FileSet name</td>  </tr>
<tr> <td>MD5</td>         <td>tinyblob</td>      <td>MD5 checksum of FileSet</td>  </tr>
</table>
<p>The <b>FileSet</b> table contains one entry for each FileSet that is used.
The MD5 signature is kept to ensure that if the user changes anything inside
the FileSet, it will be detected and the new FileSet will be used. This
is particularly important when doing an incremental update. If the user deletes
a file or adds a file, we need to ensure that a Full backup is done prior
to the next incremental.
<p>&nbsp;<p>


<!--   JobMedia Table -->
<table cellspacing="2" cellpadding="2" border="3">
<tr> <th colspan="3" align="left">JobMedia</th> </tr>
<tr> <th>Column Name</th>   <th>Data Type&nbsp;&nbsp;&nbsp;</th>    <th>Remark</th> </tr>
<tr> <td>JobMediaId</td>    <td>integer</td>      <td>Primary Key</td> </tr>
<tr> <td>JobId</td>         <td>integer</td>      <td>Link to Job Record</td>  </tr>
<tr> <td>MediaId</td>       <td>integer</td>      <td>Link to Media Record</td>  </tr>
<tr> <td>FirstIndex</td>    <td>integer</td>     <td>The index (sequence number)
          of the first file written for this Job to the Media</td>  </tr>
<tr> <td>LastIndex</td>     <td>integer</td>     <td>The index
          of the last file written for this Job to the Media</td>  </tr>
<tr> <td>StartFile</td>     <td>integer</td>      <td>The physical media (tape)
          file number of the first block written for this Job</td></tr>
<tr> <td>EndFile</td>       <td>integer</td>      <td>The physical media (tape)
          file number of the last block written for this Job</td></tr>
<tr> <td>StartBlock</td>     <td>integer</td>      <td>The number of the first
          block written for this Job</td></tr>
<tr> <td>EndBlock</td>      <td>integer</td>      <td>The number of the last
          block written for this Job</td></tr>
</table>
<p>The <b>JobMedia</b> table contains one entry for each volume written for
the current Job. If the Job spans 3 tapes, there will be three JobMedia
records, each containing the information to find all the files for the
given JobId on the tape.
<p>&nbsp;<p>

<!--   Media Table   -->
<table cellspacing="2" cellpadding="2" border="3">
<tr> <th colspan="3" align="left">Media</th> </tr>
<tr> <th>Column Name</th>    <th>Data Type&nbsp;&nbsp;&nbsp;</th>    <th>Remark</th> </tr>
<tr> <td>MediaId</td>        <td>integer</td>  <td>Primary Key</td> </tr>
<tr> <td>VolumeName</td>     <td>tinyblob</td> <td>Volume name</td>  </tr>
<tr> <td>Slot</td>           <td>integer</td>  <td>Autochanger Slot number or zero</td>  </tr>
<tr> <td>PoolId</td>         <td>integer</td>  <td>Link to Pool Record</td>  </tr>
<tr> <td>FirstWritten</td>   <td>datetime</td>  <td>Time/date when first written</td>  </tr>
<tr> <td>LastWritten</td>    <td>datetime</td>  <td>Time/date when last written</td>  </tr>
<tr> <td>LabelDate</td>      <td>datetime</td>  <td>Time/date when tape labeled</td>  </tr>
<tr> <td>VolJobs</td>        <td>integer</td>   <td>Number of jobs written to this media</td>  </tr>
<tr> <td>VolFiles</td>       <td>integer</td>   <td>Number of files written to this media</td>  </tr>
<tr> <td>VolBlocks</td>      <td>integer</td>   <td>Number of blocks written to this media</td>  </tr>
<tr> <td>VolMounts</td>      <td>integer</td>   <td>Number of time media mounted</td>  </tr>
<tr> <td>VolBytes</td>       <td>bigint</td>   <td>Number of bytes saved in Job</td>  </tr>
<tr> <td>VolErrors</td>      <td>integer</td>   <td>Number of errors during Job</td>  </tr>
<tr> <td>VolWrites</td>      <td>integer</td>   <td>Number of writes to media</td>  </tr>
<tr> <td>VolMaxBytes</td>     <td>bigint</td>  <td>Maximum bytes to put on this media</td>  </tr>
<tr> <td>VolCapacityBytes</td> <td>bigint</td> <td>Capacity estimate for this volume</td>  </tr>
<tr> <td>VolStatus</td>         <td>enum</td>    <td>Status of media: Full, Archive, Append, Recycle,
       Read-Only, Disabled, Error, Busy</td>  </tr>
<tr> <td>Recycle</td>         <td>tinyint</td>    <td>Whether or not Bacula can recycle the Volumes: Yes, No</td></tr>
<tr> <td>VolRetention</td>     <td>bigint</td>    <td>64 bit seconds until expiration</td></tr>
</table>
<p>The <b>Volume</b> table (internally referred to as the Media table)
contains one entry for each volume, that is each tape, cassette (8mm,
DLT, DAT, ...), or file on which information is or was backed up.  There
is one Volume record created for each of the NumVols specified in the
Pool resource record.
<p>&nbsp;<p>

<!--   Pool Table   -->
<table cellspacing="2" cellpadding="2" border="3">
<tr> <th colspan="3" align="left">Pool</th> </tr>
<tr> <th>Column Name</th>     <th>Data Type</th> <th>Remark</th> </tr>
<tr> <td>PoolId</td>          <td>integer</td>   <td>Primary Key</td> </tr>
<tr> <td>Name</td>            <td>Tinyblob</td>  <td>Pool Name</td>  </tr>
<tr> <td>NumVols</td>         <td>Integer</td>   <td>Number of Volumes in the Pool</td>  </tr>
<tr> <td>MaxVols</td>         <td>Integer</td>   <td>Maximum Volumes in the Pool</td>  </tr>
<tr> <td>UseOnce</td>         <td>tinyint</td>   <td>Use volume once</td>  </tr>
<tr> <td>UseCatalog</td>      <td>tinyint</td>   <td>Set to use catalog</td>  </tr>
<tr> <td>AcceptAnyVolume</td> <td>tinyint</td>   <td>Accept any volume from Pool</td>  </tr>
<tr> <td>VolRetention</td>   <td>bigint</td>   <td>64 bit seconds to retain volume</td>  </tr>
<tr> <td>AutoPrune</td>      <td>tinyint</td>   <td>Yes/no for autopruning</td>  </tr>
<tr> <td>Recyle</td>         <td>tinyint</td>   <td>Yes/no for allowing auto recycling of Volume</td>  </tr>
<tr> <td>PoolType</td>        <td>enum</td>      <td>Backup, Copy, Cloned, Archive, Migration</td>  </tr>
<tr> <td>LabelFormat</td>     <td>Tinyblob</td>  <td>Label format</td>  </tr>
</table>
<p>The <b>Pool</b> table contains one entry for each media pool
controlled by Bacula in this database.  One media record exists for each
of the NumVols contained in the Pool.  The PoolType is a Bacula defined
keyword.  The MediaType is defined by the administrator, and corresponds
to the MediaType specified in the Director's Storage definition record.
The CurrentVol is the sequence number of the Media record for the
current volume.
<p>&nbsp;<p></p>

<!--    Client Table   -->
<table cellspacing="2" cellpadding="2" border="3">
<tr> <th colspan="3" align="left">Client</th> </tr>
<tr> <th>Column Name</th>  <th>Data Type</th>    <th>Remark</th> </tr>
<tr> <td>ClientId</td>     <td>integer</td>      <td>Primary Key</td> </tr>
<tr> <td>Name</td>         <td>TinyBlob</td>     <td>File Services Name</td>  </tr>
<tr> <td>UName</td>        <td>TinyBlob</td>      <td>uname -a from Client (not yet used)</td>  </tr>
<tr> <td>AutoPrune</td>      <td>tinyint</td>   <td>Yes/no for autopruning</td>  </tr>
<tr> <td>FileRetention</td>   <td>bigint</td>   <td>64 bit seconds to retain Files</td>  </tr>
<tr> <td>JobRetention</td>   <td>bigint</td>   <td>64 bit seconds to retain Job</td>  </tr>
</table>
<p>The <b>Client</b> table contains one entry for each machine backed up
by Bacula in this database. Normally the Name is a fully qualified domain name.
<p>&nbsp;<p></p>


<!--    Version Table   -->
<table cellspacing="2" cellpadding="2" border="3">
<tr> <th colspan="3" align="left">Client</th> </tr>
<tr> <th>Column Name</th>  <th>Data Type</th>    <th>Remark</th> </tr>
<tr> <td>VersionId</td>     <td>integer</td>      <td>Primary Key</td> </tr>
</table>
<p>The <b>Version</b> table defines the Bacula database version number.
Bacula checks this number before reading the database to ensure
that it is compatible with the Bacula binary file.
<p>&nbsp;<p></p>

<h3>MySQL Table Definition</h3>
The commands used to create the MySQL tables are as follows:
<pre>
USE bacula;
CREATE TABLE Filename (
  FilenameId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  Name BLOB NOT NULL,
  PRIMARY KEY(FilenameId),
  INDEX (Name(30))
  );

CREATE TABLE Path (
   PathId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
   Path BLOB NOT NULL,
   PRIMARY KEY(PathId),
   INDEX (Path(50))
   );


# ****FIXME**** make FileId BIGINT *****
CREATE TABLE File (
   FileId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
   FileIndex INTEGER UNSIGNED NOT NULL,
   JobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
   PathId INTEGER UNSIGNED NOT NULL REFERENCES Path,
   FilenameId INTEGER NOT NULL REFERENCES Filename,
   MarkId INTEGER UNSIGNED NOT NULL DEFAULT 0,
   LStat TINYBLOB NOT NULL,
   MD5 TINYBLOB NOT NULL,
   PRIMARY KEY(FileId),
   INDEX (JobId),
   INDEX (PathId),
   INDEX (FilenameId)
   );


CREATE TABLE Job (
   JobId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
   Job TINYBLOB NOT NULL,
   Name TINYBLOB NOT NULL,
   PurgedFiles TINYINT NOT NULL DEFAULT 0,
   Type BINARY(1) NOT NULL,
   Level BINARY(1) NOT NULL,
   ClientId INTEGER NOT NULL REFERENCES Client,
   JobStatus BINARY(1) NOT NULL,
   SchedTime DATETIME NOT NULL,
   StartTime DATETIME NOT NULL,
   EndTime DATETIME NOT NULL,
   JobTDate BIGINT UNSIGNED NOT NULL,
   VolSessionId INTEGER UNSIGNED NOT NULL,
   VolSessionTime INTEGER UNSIGNED NOT NULL,
   JobFiles INTEGER UNSIGNED NOT NULL,
   JobBytes BIGINT UNSIGNED NOT NULL,
   JobErrors INTEGER UNSIGNED NOT NULL,
   JobMissingFiles INTEGER UNSIGNED NOT NULL,
   PoolId INTEGER UNSIGNED NOT NULL REFERENCES Pool,
   FileSetId INTEGER UNSIGNED NOT NULL REFERENCES FileSet,
   PRIMARY KEY(JobId),
   INDEX (Name(128))
   );

# 
CREATE TABLE FileSet (
   FileSetId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
   FileSet TINYBLOB NOT NULL,
   MD5 TINYBLOB NOT NULL,
   PRIMARY KEY(FileSetId)
   );

CREATE TABLE JobMedia (
   JobMediaId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
   JobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
   MediaId INTEGER UNSIGNED NOT NULL REFERENCES Media,
   FirstIndex INTEGER UNSIGNED NOT NULL,
   LastIndex INTEGER UNSIGNED NOT NULL,
   StartFile INTEGER UNSIGNED NOT NULL,
   EndFile INTEGER UNSIGNED NOT NULL,
   StartBlock INTEGER UNSIGNED NOT NULL,
   EndBlock INTEGER UNSIGNED NOT NULL,
   PRIMARY KEY(JobMediaId),
   INDEX (JobId, MediaId)
   );


CREATE TABLE Media (
   MediaId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
   VolumeName TINYBLOB NOT NULL,
   Slot INTEGER NOT NULL DEFAULT 0,
   PoolId INTEGER UNSIGNED NOT NULL REFERENCES Pool,
   MediaType TINYBLOB NOT NULL,
   FirstWritten DATETIME NOT NULL,
   LastWritten DATETIME NOT NULL,
   LabelDate DATETIME NOT NULL,
   VolJobs INTEGER UNSIGNED NOT NULL,
   VolFiles INTEGER UNSIGNED NOT NULL,
   VolBlocks INTEGER UNSIGNED NOT NULL,
   VolMounts INTEGER UNSIGNED NOT NULL,
   VolBytes BIGINT UNSIGNED NOT NULL,
   VolErrors INTEGER UNSIGNED NOT NULL,
   VolWrites INTEGER UNSIGNED NOT NULL,
   VolMaxBytes BIGINT UNSIGNED NOT NULL,
   VolCapacityBytes BIGINT UNSIGNED NOT NULL,
   VolStatus ENUM('Full', 'Archive', 'Append', 'Recycle', 'Purged',
    'Read-Only', 'Disabled', 'Error', 'Busy') NOT NULL,
   Recycle TINYINT NOT NULL,
   VolRetention BIGINT UNSIGNED NOT NULL,
   PRIMARY KEY(MediaId),
   INDEX (PoolId)
   );

CREATE TABLE Pool (
   PoolId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
   Name TINYBLOB NOT NULL,
   NumVols INTEGER UNSIGNED NOT NULL,
   MaxVols INTEGER UNSIGNED NOT NULL,
   UseOnce TINYINT NOT NULL,
   UseCatalog TINYINT NOT NULL,
   AcceptAnyVolume TINYINT DEFAULT 0,
   VolRetention BIGINT UNSIGNED NOT NULL,
   AutoPrune TINYINT DEFAULT 0,
   Recycle TINYINT DEFAULT 0,
   PoolType ENUM('Backup', 'Copy', 'Cloned', 'Archive', 'Migration') NOT NULL,
   LabelFormat TINYBLOB,
   UNIQUE (Name(128)),
   PRIMARY KEY (PoolId)
   );


CREATE TABLE Client (
   ClientId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
   Name TINYBLOB NOT NULL,
   Uname TINYBLOB NOT NULL,       /* full uname -a of client */
   AutoPrune TINYINT DEFAULT 0,
   FileRetention BIGINT UNSIGNED NOT NULL,
   JobRetention  BIGINT UNSIGNED NOT NULL,
   UNIQUE (Name(128)),
   PRIMARY KEY(ClientId)
   );

CREATE TABLE Version (
   VersionId INTEGER UNSIGNED NOT NULL 
   );

-- Initialize Version            
INSERT INTO Version (VersionId) VALUES (2);

CREATE TABLE Counters (
   Counter TINYBLOB NOT NULL,
   PoolId INTEGER UNSIGNED NOT NULL REFERENCES Pool,
   MinValue INTEGER,
   MaxValue INTEGER,
   CurrentValue INTEGER,
   WrapCounter TINYBLOB NOT NULL
   );

</pre>

<page_prev name="Bacula File Services" url="file.html">
<page_next name="Internal Component Designs" url="internals.html">
