Files
secondo/include/SecondoSMI.h
2026-01-23 17:03:45 +08:00

2073 lines
61 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2004, University in Hagen, Department of Computer Science,
Database Systems for New Applications.
SECONDO 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.
SECONDO 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 SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
//paragraph [10] title: [{\Large \bf ] [}]
//paragraph [21] table1column: [\begin{quote}\begin{tabular}{l}] [\end{tabular}\end{quote}]
//paragraph [22] table2columns: [\begin{quote}\begin{tabular}{ll}] [\end{tabular}\end{quote}]
//paragraph [23] table3columns: [\begin{quote}\begin{tabular}{lll}] [\end{tabular}\end{quote}]
//paragraph [24] table4columns: [\begin{quote}\begin{tabular}{llll}][\end{tabular}\end{quote}]
//[--------] [\hline]
//characters [1] verbatim: [$] [$]
//characters [2] formula: [$] [$]
//characters [3] capital: [\textsc{] [}]
//characters [4] teletype: [\texttt{] [}]
//[ae] [\"a]
//[oe] [\"o]
//[ue] [\"u]
//[ss] [{\ss}]
//[<=] [\leq]
//[#] [\neq]
//[_] [\_]
//[tilde] [\verb|~|]
1 Header File: Storage Management Interface
April 2002 Ulrich Telle
November 30, 2002 RHG Added function ~GetKey~.
April, 2004. F.Hoffmann changed implementation details of static method
'ListDatabases'.
Aug 18, 2004. M. Spiekermann added ~Setflag\_NOSYNC~ to speed up closing files
at the end of a query. Since queries does not modify the data synchronisation is
not necessary.
Sept 15, 2004. M. Spiekermann. Declaration of SmiError moved to ErrorCodes.h.
Nov 2004. M. Spiekermann. Some functions were implemented as inline functions.
Feb. 2006. M. Spiekermann Some new functions were declared which allow to set up
only a temporary BDB-Environment needed for the implementation of persistent
nested lists.
1.1 Overview
The *Storage Management Interface* provides all types and classes needed
for dealing with persistent data objects in "Secondo"[3].
Essential for all operations on persistent data objects is the class
~SmiEnvironment~ which provides methods for startup and shutdown of
the storage management, for transaction handling and for error handling.
Internally the ~SmiEnvironment~ handles the connection to the underlying
implementation of the persistent information storage management. Currently
implementations based on the "Berkeley DB"[3] library and on the "Oracle"[3]
DBMS are available. The decision which implementation is used is taken at link
time of the "Secondo"[3] server. Fine tuning of implementation dependent
parameters is done by means of a configuration file which is read at system
startup. For future extensions (i.e. user management and access control)
it is possible to store the current user identification in the ~SmiEnvironment~.
Additionally the ~SmiEnvironment~ introduces the concept of ~databases~. Within
one ~SmiEnvironment~ there may exist several databases, but a user may access
only *one* database at a single time. A valid database name consists of at most
"SMI\_MAX\_DBNAMELEN"[4] (currently 15) alphanumeric characters or underscores.
The first character has to be alphabetic. Database names are *not* case
sensitive.
Persistent objects are stored as records in so called ~SmiFiles~. An ~SmiFile~
is a handle to its representation in the interface implementation. Two kinds
of ~SmiFiles~ are provided: one for record oriented access and one for key
oriented access. An ~SmiFile~ always has a ~context~, default or user specified.
The context allows to adjust implementation dependent parameters to benefit
from special knowledge about the objects to be stored in this context. These
parameters are specified in the configuration file under the appropriate
context section heading.
An ~SmiFile~ is always represented by a unique numeric identifier. Additionally
it may have a name. Without a name an ~SmiFile~ is said to be ~anonymous~.
Within a context a name must be unique. ~SmiFile~ names and context names are
case sensitive and may have at most "SMI\_MAX\_NAMELEN"[4] (currently 31)
alphanumeric characters or underscores. The first character has to be
alphabetic.
An ~SmiFile~ for record oriented access is called ~SmiRecordFile~.
Records can be of fixed or variable size. The use of ~SmiFiles~ with fixed
length records is recommended whereever appropriate since they may be more
efficient -- depending on the implementation. Records can only be appended
to the end of an ~SmiFile~,
but can be accessed for reading, update or deletion in random order using their
record number. An iterator for sequential access to all records of an ~SmiFile~
is provided.
An ~SmiFile~ for key oriented access is called ~SmiKeyedFile~, which is itself
divided into two kinds, called ~SmiBtreeFile~ and ~SmiHashFile~, depending on
the storage method, a B-Tree and a Hash, respectively. An ~SmiKeyFile~ is
capable of holding pairs of keys and data. Both keys and data may be of variable
size. While the size of the data is only restricted by physical limits of the
available hardware, the size of keys is restricted to at most 4000 bytes.
(This limit is imposed by the VARCHAR2 datatype of "Oracle"[3], but depending
on the actual database configuration the maximal possible key length might be
lower.
Other relational database systems allow only much smaller keys, i.e. "MySQL"[3]
restricts the combined key length to 512 bytes, but a single column key cannot
exceed 255 bytes and that would be the restriction for an implementation based
on "MySQL"[3].)
As key types signed integers, floating point numbers, and strings are supported.
Keys may also have a more complex structure as long as the user provides a
function for mapping a key to a byte string which obeys to a lexical order.
Keys may be unique or may allow for duplicate data. The use of iterators is
mandatory for access to duplicates. Iterators for access to all records or
records within a specified range of keys are provided.
An ~SmiRecord~ handle is used to access complete or partial records of an
~SmiFile~.
1.2 Transaction handling
The storage management interface provides methods to start, commit and abort
transactions. All access to persistent objects should be done within user
transactions. User transactions are *not* started automatically. Due to
limitations of the transaction support of the "Berkeley DB"[3] it is
recommended that applications using this interface should run in a sort of
auto-commit mode by surrounding very few atomic operations with calls to
the start and commit transaction methods.
Only application which are able to repeat transactions easily in case of failure
may use more complex transactions.
Although both current implementations of the storage
management interface support transaction logic for data manipulation statements,
there is no support for transaction logic for data definition statements
(creation and deletion of ~SmiFiles~). Therefore the update of the SmiFile
catalog and the deletion of ~SmiFiles~ are postponed until completion or
rollback of a transaction. If the ~SmiFile~ catalog update fails, the
transaction is aborted and rolled back automatically.
1.3 Interface methods
The class ~SmiEnvironment~ provides the following methods:
[23] Environment & Transaction handling & Error handling \\
[--------]
StartUp & BeginTransaction & CheckLastErrorCode \\
ShutDown & CommitTransaction & GetLastErrorCode \\
SetUser & AbortTransaction & SetError \\
CreateDatabase & & \\
OpenDatabase & & \\
CloseDatabase & & \\
EraseDatabase & & \\
ListDatabases & & \\
IsDatabaseOpen & & \\
CurrentDatabase & & \\
The classes ~SmiRecordFile~ and ~SmiKeyedFile~ inherit the following methods
from their base class ~SmiFile~:
[23] Creation/Removal & Open/Close & Information \\
[--------]
Create & Open & GetContext \\
Drop & Close & GetName \\
Truncate & & GetFileId \\
& & IsOpen \\
The class ~SmiRecordFile~ provides the following methods:
[23] Creation/Removal & Record Selection & Record Modification \\
[--------]
SmiRecordFile & SelectRecord & AppendRecord \\
[tilde]SmiRecordFile & SelectAll & DeleteRecord \\
GetData & & \\
The class ~SmiKeyedFile~ provides the following methods:
[23] Creation/Removal & Record Selection & Record Modification \\
[--------]
SmiKeyedFile & SelectRecord & InsertRecord \\
[tilde]SmiKeyedFile & & DeleteRecord \\
The class ~SmiBtreeFile~ provides the following methods:
[23] Creation/Removal & Record Selection \\
[--------]
SmiBtreeFile & SelectRange \\
[tilde]SmiBtreeFile & SelectLeftRange \\
& SelectRightRange \\
The class ~SmiBtreeFile~ provides only the creation and removal functions, since
all its functionality is provided in the ~SmiKeyedFile~:
[23] Creation/Removal \\
[--------]
SmiHashFile \\
[tilde]SmiHashFile \\
The class ~SmiRecord~ provides the following methods:
[23] Creation/Removal & Persistence & Querying \\
[--------]
SmiRecord & Read & Size \\
[tilde]SmiRecord & Write & \\
Finish & Truncate & Resize \\
The classes ~SmiRecordFileIterator~ and ~SmiKeyedFileIterator~ provide the
following methods:
[23] Creation/Removal & Access & Querying \\
[--------]
SmiRecordFileIterator & Next & EndOfScan \\
[tilde]SmiRecordFileIterator & DeleteCurrent & \\
SmiKeyedFileIterator & Restart & \\
[tilde]SmiKeyedFileIterator & Finish & \\
The class ~SmiKey~ provides the following methods:
[23] Creation/Removal & Access & Key mapping \\
[--------]
SmiKey & GetKey & Map \\
[tilde]SmiKey & KeyDataType & Unmap \\
1.4 Imports, Constants, Types
*/
#ifndef SECONDO_SMI_H
#define SECONDO_SMI_H
#include <string>
#include <vector>
#include <map>
#include <utility>
#include <db_cxx.h>
#include <string.h>
#include "ErrorCodes.h"
#include "SecondoConfig.h"
#include "CacheInfo.h"
#ifdef THREAD_SAFE
#include <boost/thread.hpp>
#endif
#ifdef SM_FILE_ID
#include <boost/interprocess/shared_memory_object.hpp>
#endif
class IndexableAttribute;
const std::string::size_type SMI_MAX_NAMELEN = 31;
/*
Specifies the maximum length of a context or file name.
*/
const std::string::size_type SMI_MAX_DBNAMELEN = 15;
/*
Specifies the maximum length of a database name.
*/
const std::string::size_type SMI_MAX_KEYLEN = 3200;
/*
Specifies the maximum length of keys.
*NOTE*: The maximum length of keys depends on several factors,
namely the storage management system and physical properties
of the underlying system:
[23] System & Blocksize & Max. key length \\
[--------]
Berkeley DB & & 4000 \\
MySQL & & 255 \\
Oracle 8i & 2 kB & 758 \\
Oracle 8i & 4 kB & 1578 \\
Oracle 8i & 8 kB & 3218 \\
Oracle 8i & 16 kB & 4000 \\
*/
const std::string::size_type SMI_MAX_KEYLEN_LOCAL = 32;
/*
Specifies the maximum length of keys which are stored locally within an
instance of the ~SmiKey~ class. Extra memory is allocated for longer keys.
*/
typedef unsigned long SmiFileId;
/*
Is the type for the unique file identifiers.
*/
typedef db_recno_t SmiRecordId;
/*
Is the type for record identifiers.
*/
typedef size_t SmiSize;
/*
Is the type for record sizes or offsets.
*/
class PrefetchingIterator;
/* Forward declaration */
typedef std::vector<std::pair<std::string,std::string> > SmiStatResultType;
/* Used by SmiFile::GetFileStatistics(...) */
enum SMI_STATS_MODE {SMI_STATS_EAGER, SMI_STATS_LAZY};
/* Used by SmiFile::GetFileStatistics(...) */
/**************************************************************************
1.3 Class "SmiKey"[1]
The class ~SmiKey~ is used to store key values of different types in a
consistent manner. Key values are restricted in length to at most
"SMI\_MAX\_KEYLEN"[4] bytes. If the length of the key value is less than
"SMI\_MAX\_KEYLEN\_LOCAL"[4] the key value ist stored within the class
instance, otherwise memory is allocated.
*/
class SMI_EXPORT SmiKey
{
public:
enum KeyDataType
{ Unknown, Integer, Longint, Float, String, Composite };
/*
Lists the types of key values supported by the ~SmiFiles~ for keyed access:
* *Unknown* -- not a true type, designates an uninitialized key instance
* *RecNo* -- a record number of a ~SmiRecordFile~
* *Integer* -- signed integer number (base type ~int32[_]t~)
* *Longint* -- signed integer number (base type ~int64[_]t~)
* *Float* -- floating point number (base type ~double~)
* *String* -- character string (base type ~string~)
* *Composite* -- user-defined key structure, the user has to provide a mapping
function which is called to map the key structure to a byte string which can
be sorted like a usual string in lexical order. On key retrieval the function
is called to unmap the byte string to the user-defined key structure.
*/
static KeyDataType getKeyType(const int32_t){
return Integer;
}
static KeyDataType getKeyType(const uint32_t){
return Integer;
}
static KeyDataType getKeyType(const int64_t){
return Longint;
}
static KeyDataType getKeyType(const uint64_t){
return Longint;
}
static KeyDataType getKeyType(const double){
return Float;
}
static KeyDataType getKeyType(const std::string&){
return String;
}
static KeyDataType getKeyType(const IndexableAttribute*){
return Composite;
}
SmiKey();
SmiKey( const int32_t key );
SmiKey( const int64_t key );
SmiKey( const uint32_t key );
SmiKey( const uint64_t key );
SmiKey( const double key );
SmiKey( const std::string& key );
SmiKey( const IndexableAttribute* key );
SmiKey( const SmiKey& other );
/*
Creates a key with a type according to the constructor argument.
*/
~SmiKey();
/*
Destroys a key.
*/
SmiKey& operator=( const SmiKey& other );
bool operator==( const SmiKey& other ) const;
bool operator>( const SmiKey& other ) const;
KeyDataType GetType() const;
/*
Returns the type of the key.
*/
bool GetKey( int32_t& key )const;
bool GetKey( int64_t& key )const;
bool GetKey( uint32_t& key )const;
bool GetKey( uint64_t& key )const;
bool GetKey( double& key )const;
bool GetKey( std::string& key )const;
bool GetKey( IndexableAttribute* key )const;
/*
Returns the value of the key. The argument type must match the type of the key!
*/
SmiSize GetLength() const;
/*
Returns the length of the key if the key is a composite key, otherwise -1 is
returned.
*/
static void Map( const int32_t inData, void* outData );
static void Map( const int64_t inData, void* outData );
static void Map( const uint32_t inData, void* outData );
static void Map( const uint64_t inData, void* outData );
static void Map( const double inData, void* outData );
static void Unmap( const void* inData, int32_t& outData );
static void Unmap( const void* inData, int64_t& outData );
static void Unmap( const void* inData, uint32_t& outData );
static void Unmap( const void* inData, uint64_t& outData );
static void Unmap( const void* inData, double& outData );
/*
These functions are provided for convenience. They may be used in user-defined
mapping functions to map integer and floating-point numbers to lexical byte
strings and vice versa.
*/
protected:
private:
void FreeData();
/*
Frees the memory allocated for a key, if memory was previously allocated.
The function is called internally when a new key value is assigned.
*/
const void* GetAddr() const;
/*
Returns the memory address of the key value.
*/
void SetKey( const int32_t key );
void SetKey( const int64_t key );
void SetKey( const uint32_t key );
void SetKey( const uint64_t key );
void SetKey( const double key );
void SetKey( const std::string& key );
void SetKey( const IndexableAttribute* key );
void SetKey( const KeyDataType kdt,
const void* key, const SmiSize keyLen );
/*
Sets the internal key value to the passed key value, setting also the key type.
*/
KeyDataType keyType; // Type of the key value
SmiSize keyLength; // Size of the key value in bytes
union // Structure for storing the key
{
int32_t integerKey;
int64_t longintKey;
double floatKey;
char shortKeyData[SMI_MAX_KEYLEN_LOCAL+1];
char* longKeyData;
};
friend class SmiFile;
friend class SmiFileIterator;
friend class SmiRecordFile;
friend class SmiKeyedFile;
friend class SmiBtreeFile;
friend class SmiKeyedFileIterator;
friend class SmiRecord;
friend class PrefetchingIterator;
};
/**************************************************************************
1.3 Class "SmiFile"[1]
This class provides the methods common to both ~SmiRecordFiles~ and
~SmiKeyedFiles~.
*/
class SMI_EXPORT SmiFile
{
public:
enum FileType { FixedLength, VariableLength, KeyedBtree, KeyedHash };
/*
Is an enumeration of possible file types:
* *FixedLength* -- Files of this type consist of a set of records all having a
fixed size which cannot be changed.
A record is filled with binary null characters if not the whole record is
written. Depending on the implementation this file type allows for better
locking characteristics in multi-user environments. Records are identified
by record numbers.
* *VariableLength* -- Files of this type consist of a set of records of
potentially varying size. Records are identified by record numbers.
* *Keyed* -- Files of this type consist of key/data pairs.
*/
enum AccessType { ReadOnly, Update };
/*
Is an enumeration of possible access types:
* *ReadOnly* -- Records are selected for read access only. Operations
which change the contents or the size of a record are not permitted.
* *Update* -- Records are selected for read and/or write access.
*/
bool Create( const std::string& name, const std::string& context = "Default",
uint16_t pageSize = 0, const bool keepId = false );
/*
Creates a new SmiFile with given name.
If the name is an empty string, the name is constructed automatically.
The context string should be one
of them available in the underlying storage manager. If the pagesize
is set to 0 (default), the page size of the filesystem is used.
If keepId is set to true, the old fileId is reused instead of creating
a new one for this file.
*/
bool Create( const std::string& context = "Default", uint16_t pageSize = 0 );
/*
Creates a new anonymous ~SmiFile~.
Optionally a ~context~ can be specified. If pageSize equals 0, the size
configured in SecondoConfig.ini will be used otherwise a system dependent
default value is used.
*/
bool ReCreate();
/*
Removes the underlying file and creates a new one with same name, context,
pagesize, and fileId.
*/
bool Open( const SmiFileId id, const std::string& context = "Default" );
/*
Opens an existing anonymous ~SmiFile~ using its file identifier ~id~.
Optionally a ~context~ can be specified.
*/
bool Open( const std::string& name, const std::string& context = "Default" );
/*
Opens an existing named ~SmiFile~ or creates a new named ~SmiFile~ if it does
not exist. Optionally a ~context~ can be specified.
*/
bool Close(const bool sync = true );
/*
Closes an open ~SmiFile~.
*/
bool Drop();
/*
Erases a ~SmiFile~. It is necessary to close any record iterators or record
handles before dropping a ~SmiFile~.
*/
bool Truncate();
/*
Empties an ~SmiFile~. It is necessary to close any record iterators or record
handles before truncating it. This method is only used to free disk data for
tuple buffers since the Remove() operation does not work for them (bug?).
Without this compromise solution the data would only be deleted when secondo
shuts down.
*/
bool Remove();
/*
Removes a ~SmiFile~ from disk. It is necessary to close any record iterators
or record handles before calling this function.
*/
std::string GetContext();
/*
Returns the context of the ~SmiFile~.
*/
std::string GetName();
/*
Returns the name of a named ~SmiFile~ or an empty string for an anonymous
~SmiFile~.
*/
SmiFileId GetFileId();
/*
Returns the unique ~SmiFile~ identifier.
*/
SmiSize GetRecordLength() { return fixedRecordLength; }
/*
Returns the length of fixed Records. In the case of variable record length 0
is returned.
*/
uint16_t GetPageSize() const;
/*
Returns the page size of the file.
*/
bool IsOpen();
/*
Returns whether the ~SmiFile~ handle is open and can be used to access the
records of the ~SmiFile~.
*/
std::ostream& Print(std::ostream& os) const;
SmiStatResultType GetFileStatistics(const SMI_STATS_MODE mode);
/*
Returns a SmiStatResultType, which is a vector of key-value pairs. Both, keys
and values are strings. Each ~key~ describes a statistic on the file and the
~value~ the according value.
~mode~ is of type SMI\_STATS\_MODE: either SMI\_STATS\_EAGER, SMI\_STATS\_LAZY.
~SMI\_STATS\_EAGER~ will force the active collection of statistics to ensure
that current and complete data is returned (that migth take a while, for data
may needed to be analyzed), while ~SMI\_STATS\_LAZY~ will only read out
(possibly old) statistics and/or return incomplete data.
Different SmiFile types may return different sets of keys as results.
*/
bool IsTemp();
std::string GetFileName() const {
return fileName;
}
protected:
SmiFile( const bool isTemporary = false);
SmiFile( const SmiFile& smiFile );
~SmiFile();
bool CheckName( const std::string& name );
bool useTxn;
/*
Checks whether the given name ~name~ is valid.
*/
bool opened; // Open state of SmiFile
std::string fileContext; // Name of file context
std::string fileName; // Name of named SmiFile
SmiFileId fileId; // Unique file identifier
FileType fileType; // Type of SmiFile records
SmiSize fixedRecordLength; // Length of records with
// fixed length
bool uniqueKeys; // Uniqueness of keys
SmiKey::KeyDataType keyDataType; // Data type of keys
class Implementation;
Implementation* impl;
private:
bool trace;
friend class SmiEnvironment;
friend class SmiFileIterator;
friend class SmiRecord;
};
std::ostream& operator<<(const std::ostream& os, const SmiFile& f);
class SMI_EXPORT SmiCachedFile : public SmiFile
{
protected:
SmiCachedFile( const bool isTemporary, const uint64_t cache_sz = 0 );
SmiCachedFile( const SmiCachedFile& f );
~SmiCachedFile();
uint64_t GetCacheSize() const;
/*
Returns the cache size of the file.
*/
private:
uint64_t cacheSize;
friend class SmiEnvironment;
friend class SmiFileIterator;
friend class SmiRecord;
};
/*
1 Declaration of the Storage Management Interface for UrelAlgebra
1.1 Overview
The storage management interface of the UrelAlgebra
supports basic I/O methods for let urel object to access
the memory pool file in the Berkely DB environment.
This is one part of the whole storage management interface
of the Secondo system.
The interface is composed by two classes, *SmiUpdateFile*
and *SmiUpdatePage*. The SmiUpdateFile provides methods
for accessing the whole file of an urel object. The main methods
are listed below:
* Create
* Open
* Close
* AppendNewPage
* GetPage
* PutPage
Create is used to create a new memory pool file, and use Open
method to access an exist memory pool file, then use Close method
to flush all unsaved data to the disk and release the handle to the file.
AppendNewPage is used to add a new page in this file, and use the
GetPage method to map an exist page in the disk file to the main memory,
and lock that part of memory so that different processes can share
the same page, that's what we call pin that page in the memory.
When the page is useless, then use PutPage method to flush the data back
to the disk file, and unpin the page.
The SmiUpdatePage provides access methods to one page in the
memory pool file. There are two main methods: read and write,
with which we can read and write any type of data in this page.
1.2 Definition of Class SmiUpdatePage
*/
class SMI_EXPORT SmiUpdatePage
{
public:
SmiUpdatePage();
SmiUpdatePage(const SmiUpdatePage& rhs);
~SmiUpdatePage();
/*
3.1.1 The write method of SmiUpdatePage
Write the data in the ~buffer~ to the page at the ~offset~ place.
*/
SmiSize Write(const void* buffer, const SmiSize numberOfBytes,
SmiSize offset = 0)
{
memcpy((char*) pagePt + offset, buffer, numberOfBytes);
return numberOfBytes;
}
/*
3.1.2 The read method of SmiUpdatePage
Read the data at the ~offset~ place of the page back to the ~buffer~.
*/
SmiSize Read(void* buffer, const SmiSize numberOfBytes,
SmiSize offset = 0)
{
memcpy(buffer, (char*) pagePt + offset, numberOfBytes);
return numberOfBytes;
}
template<typename T>
inline SmiSize
Write(T& buffer)
{
SmiSize n = Write(&buffer, sizeof(T));
return n;
}
template<typename T>
inline SmiSize
Read(T& buffer)
{
SmiSize n = Read(&buffer, sizeof(T));
return n;
}
//auxiliary functions
void* GetPageAddr();
db_pgno_t GetPageNo();
SmiSize GetPageSize();
bool isAvailable();
private:
db_pgno_t pageNo; //Indicate the page number inside the file
SmiSize pageSize;
void* pagePt; //The pointer point to the update page
friend class SmiUpdateFile;
};
/*
1.3 Definition of Class SmiUpdateFile
The first several pages of the memory pool file is called ~system page~,
which is used to store some systematic information of the file.
At present there is only one system page, and only count how many
processes are sharing this file.The page number of the update file
is started from 1.
For effective access the memory, the pointers of all pages got from
the disk file will be kept in a STL map structure, so that we can get the
memory pointer directly.
*/
struct SmiUpdateSysPage
{
SmiUpdateSysPage() :
shareByNum(0)
{}
int shareByNum; //count the number of processes sharing this file
};
class SMI_EXPORT SmiUpdateFile : public SmiFile
{
public:
SmiUpdateFile();
~SmiUpdateFile();
SmiUpdateFile(SmiSize _poolPageSize);
bool Open(const std::string& name); //only use in test example
bool Open(const SmiFileId _fID, const SmiSize _pSize,
bool isInitialized = true);
//used to reopen an exist file
bool Close();
bool Create(const std::string& context = "Default", uint16_t pageSize = 0);
//used to create a new file
//New methods about getting and putting pages
bool AppendNewPage(SmiUpdatePage*& page);
bool GetPage(const db_pgno_t pageNo, SmiUpdatePage*& page);
bool PutPage(const db_pgno_t pageNo, bool isChanged = true);
//Auxiliary functions ...
SmiSize GetPoolPageSize();
int GetSysPageNum();
bool GetIniStatus();
int GetExistPageNum();
private:
DbMpoolFile *dbMpf; //The pointer to the memory pool file
SmiSize poolPageSize;
// The page size of the memory pool file
int sysPageNum;
// The number of pages need to record system info
int existPageNum;
// The numbers of pages exist in the disk file currently
bool isInitialized;
// Make sure that this file is not empty.
std::map<db_pgno_t, SmiUpdatePage*> gotPages;
bool SyncFile();
bool InitializePoolFile();
int GetNumOfShareProcess();
int GetFactPageNum();
//Get how many processes are sharing this file
bool RegisterInFile();
bool UnRegisterInFile();
};
/**************************************************************************
1.3 Class "SmiEnvironment"[1]
This class handles all aspects of the environment of the storage
environment including the basics of transactions.
*/
class SMI_EXPORT SmiEnvironment
{
public:
enum SmiType { SmiBerkeleyDB, SmiOracleDB };
/*
Enumerates the different implementations of the storage management interface:
* *SmiBerkeleyDB* -- Implementation based on the "Berkeley DB"[3]
* *SmiOracleDB* -- Implementation based on "Oracle"[3]
*/
enum RunMode { SingleUserSimple, SingleUser,
MultiUser, MultiUserMaster };
/*
Lists the types of run modes supported by the ~SmiEnvironment~:
* *SingleUserSimple* -- access to the ~SmiEnvironment~ is restricted to
exactly *one* single process. Not observing this restriction can
cause unpredictable behavior and possibly database corruption.
Transactions and logging are usually disabled. Using this mode is not
recommended, except for read-only databases.
* *SingleUser* -- access to the ~SmiEnvironment~ is restricted to
exactly *one* single process. Not observing this restriction can
cause unpredictable behavior and possibly database corruption.
Transactions and logging are enabled.
* *MultiUser* -- the ~SmiEnvironment~ may be accessed by more than
one process. Transactions, logging and locking are enabled.
* *MultiUserMaster* -- the ~SmiEnvironment~ may be accessed by more
than one process. Transactions, logging and locking are enabled.
This mode should be used by the process which acts as the dispatcher
for client requests to allow additional implementation dependent
initialization.
*NOTE*: In any multi user mode the "Secondo"[3] registrar must be running.
The behaviour of the storage management system in single user mode is
implementation dependent.
*/
static std::map<SmiError, std::string> errorMap;
/*
A table containing the error map strings indexed by error numbers (~SmiError~).
The function ~Err2Msg~ retrieves the strings from this table.
*/
static bool errorMapInitialized;
/*
A flag that indicates whether the error map table is already initialized.
*/
static SmiType GetImplementationType();
/*
Returns the implementation type of the storage management interface.
*NOTE*: This information is availabe before calling the ~StartUp~ method,
thus allowing to perform implementation dependent activities.
*/
static SmiEnvironment* GetInstance();
/*
Returns a pointer to the "Secondo"[3] Storage Management Environment
(seldom needed).
*/
static std::string GetSecondoHome();
static std::string ConfigFile();
static int CreateTmpEnvironment(std::ostream& err);
static int DeleteTmpEnvironment();
static bool StartUp( const RunMode mode,
const std::string& parmFile,
const std::string& dbDir,
std::ostream& errStream,
const std::string& port);
/*
Initializes the ~SmiEnvironment~ of the storage manager interface.
Parameters are read from the configuration file ~parmFile~.
Error messages are written to the provided output stream ~errStream~.
A user transaction is implicitly started.
*/
static bool ShutDown();
/*
Shuts down the storage manager interface. An open user transaction is aborted
implicitly. It is necessary to close *all* open ~SmiFiles~, iterators and
record handles before shutting down the system.
*/
static bool IsDatabaseOpen();
/*
Returns "true"[4] if a database is currently open, otherwise "false"[4] is
returned.
*/
static std::string CurrentDatabase();
/*
Returns the name of the currently open database. If no database is open
a blank string is returned.
*/
static bool CreateDatabase( const std::string& dbname );
/*
Creates a new "Secondo"[3] database under the name ~dbname~.
The function returns "true"[4], if the database could be created;
it returns "false"[4], if a database with the given name already
exists or if an error occured.
*/
static SI_Error OpenDatabase( const std::string& dbname );
/*
Opens an existing "Secondo"[3] database having the name ~dbname~.
The functions returns "true"[4], if the database could be opened,
otherwise it returns "false"[4].
*/
static bool CloseDatabase();
/*
Closes a previously created or opened "Secondo"[3] database.
The function returns "true"[4], if the database could be closed successfully.
Otherwise it returns "false"[4].
*/
static bool EraseDatabase( const std::string& dbname );
/*
Erases the "Secondo"[3] database named ~dbname~.
The function returns "true"[4], if the database could be erased.
Otherwise it returns "false"[4].
*NOTE*: It is an error to call this function, if a database is already
open, regardless of the name.
*/
static bool ListDatabases( std::string& dbname );
/*
Lists the names of existing databases in ~dbname~, separated by a '\#'
character. Returns true, if the execution was successful.
*/
static bool SetUser( const std::string& uid );
/*
Stores the identification ~uid~ of the current user in the ~SmiEnvironment~.
In a future extension it may be used for user management and access control.
*/
static void SetFlag_NOSYNC(const bool value) { dontSyncDiskCache = value; }
/*
Indicates that the cache in memory and the files on disk need no syncronisation.
In the Berkeley-DB Implementation this is used to speed up the DB-close() API
call at the end of a query which does no modifications to the stored data.
*/
static bool BeginTransaction();
static bool CommitTransaction(const bool closeDbHandles = true);
static bool AbortTransaction();
/*
Are provided for transaction handling. Transactions are never implicitly
started.
Therefore an explicit call to ~BeginTransaction~ is always necessary. To be able
to rollback requests for deleting ~SmiFiles~ such requests are registered
throughout the transaction and carried out only if the transaction completes
successfully. ~Named SmiFiles~ are registered in a file catalog. Changes to
this catalog take place when a transaction is committed. When updates to the
file catalog fail, the transaction is implicitly aborted.
*/
static int GetNumOfErrors();
static SmiError GetLastErrorCode();
static SmiError GetLastErrorCode( std::string& errorMessage );
/*
Returns the error code of the last storage management operation.
~CheckLastErrorCode~ provides the error code without resetting the internal
error code while the other functions reset the internal error code.
Optionally the accompanying error message is returned.
*/
static void SetSmiError( const SmiError smiErr,
const std::string& file, int pos,
const std::string& descr);
static void SetSmiError( const SmiError smiErr,
const int sysErr, const std::string& file, int pos,
const std::string& desc );
static void ResetSmiErrors();
#define SetError(code) SetSmiError(code, __FILE__, __LINE__,"")
#define SetError2(code, msg) SetSmiError(code, msg, __FILE__, __LINE__, "")
#define SetBDBError(code) SetSmiError(E_SMI_BDB, code, __FILE__, __LINE__, "")
#define SetBDBErrorD(code, desc) SetSmiError(E_SMI_BDB, code, __FILE__,\
__LINE__,desc)
/*
Allows to set an SmiError code and a system error code or an error message.
*/
static bool GetCacheStatistics(CacheInfo& ci, std::vector<FileInfo*>& fi);
static void UpdateCatalog();
static void SetAutoRemoveLogs(const bool enable);
/*
Forces the deletion of non required log files. Disables catastropic recovery.
*/
static const std::string Err2Msg( SmiError code );
/*
Translate an SMI error code into a message!
*/
static bool correctFileId();
private:
#ifdef THREAD_SAFE
static boost::recursive_mutex env_mtx;
#endif
#ifdef SM_FILE_ID
static boost::interprocess::shared_memory_object* file_id_shm;
static boost::interprocess::named_mutex file_id_mutex;
#endif
SmiEnvironment();
/*
Creates an instance of the ~Storage Management Interface~ environment.
*/
~SmiEnvironment();
/*
Destroys a ~Storage Management Interface~ environment.
*/
SmiEnvironment( SmiEnvironment& );
/*
The copy constructor is not implemented.
*/
static bool SetDatabaseName( const std::string& dbname );
/*
Checks whether the given database name ~dbname~ is valid or not,
converts the name to all lower case and stores the converted name in a
member variable.
The function returns "true"[4], if the name is valid.
A valid database name consists of at most "SMI\_MAX\_DBNAMELEN"[4]
(currently 15) alphanumeric characters or underscores. The first
character has to be alphabetic.
Database names are *not* case sensitive.
*/
static bool SetHomeDir(const std::string& dbDir);
static bool InitializeDatabase();
/*
Initializes a new database.
*/
static bool RegisterDatabase( const std::string& dbname );
/*
Registers the database ~dbname~ when it is created or opened.
The function returns "true"[4], if the database could be registered successfully
or if the application runs in single user mode.
*NOTE*: The registration is necessary to protect a database from accidental
deletion by another user.
*/
static bool UnregisterDatabase( const std::string& dbname );
/*
Unregisters the database ~dbname~.
The function returns "true"[4], if the database could be unregistered
successfully or if the application runs in single user mode.
*/
static bool LockDatabase( const std::string& dbname );
/*
Locks the database ~dbname~.
The function returns "true"[4], if a lock could be acquired successfully,
i.e. no other user accesses the database,
or if the application runs in single user mode.
*NOTE*: Before a database can be erased it has to be locked.
*/
static bool UnlockDatabase( const std::string& dbname );
/*
Unlocks the database ~dbname~.
The function returns "true"[4], if the lock could be released successfully
or if the application runs in single user mode.
*/
static void SetSmiError( const SmiError smiErr,
const std::string& errMsg, const std::string& file, int pos,
const std::string& desc );
static bool CallRegistrar( const std::string& dbname,
const std::string& cmd, std::string& answer );
/*
Auxiliary function to handle communication with the registrar process
*/
static SmiEnvironment instance; // Instance of environment
static SmiError lastError; // Last error code
static std::string lastMessage; // Last error message
static int numOfErrors; // Last error message
static bool smiStarted; // Flag SMI initialized
static bool singleUserMode;
static bool useTransactions;
// the next member is used in the Berkeley-DB Implementation
static bool dontSyncDiskCache;
static std::string configFile; // Name of config file
static std::string uid; // ID of Secondo user
static bool dbOpened; // Flag database opened
static std::string database; // Name of current database
static std::string registrar; // Name of the registrar
static SmiType smiType; // Implementation type
class Implementation;
Implementation* impl;
friend class Implementation;
friend class SmiFile;
friend class SmiFile::Implementation;
friend class SmiFileIterator;
friend class SmiRecordFile;
friend class SmiKeyedFile;
friend class SmiBtreeFile;
friend class SmiRecord;
friend class SmiUpdateFile;
};
/**************************************************************************
1.3 Class "SmiRecord"[1]
This class provides a record handle for processing data records. A record
contains user-defined byte strings of arbitrary length. A record handle is
initialized by the appropriate methods of a ~SmiFile~. After initialization
the handle can be used to access complete or partial records.
*/
class SMI_EXPORT SmiRecord
{
public:
SmiRecord();
/*
Creates a record handle. A handle is passed to ~SmiFile~ or ~SmiFileIterator~
methods for initialization and can be used thereafter to access a record.
*/
~SmiRecord();
/*
Destroys a record handle.
*/
SmiSize Read( void* buffer,
const SmiSize numberOfBytes,
const SmiSize offset = 0 );
template <typename T>
inline SmiSize Read(T& buffer) {
SmiSize n = Read(&buffer, sizeof(T), pos);
pos += sizeof(T);
return n;
}
/*
Reads a sequence of at most ~numberOfBytes~ bytes from the record into
the ~buffer~ provided by the user. Optionally a record ~offset~ can
be specified. The amount of bytes actually transfered is being returned.
*/
char* GetData(SmiSize& length);
/*
Returns the complete content of that record. The caller of that function
is responsible to free the data pointer.
*/
SmiSize Write( const void* buffer,
const SmiSize numberOfBytes,
const SmiSize offset = 0 );
template <typename T>
inline SmiSize Write(T& buffer) {
SmiSize n = Write(&buffer, sizeof(T), pos);
pos += sizeof(T);
return n;
}
/*
Writes a sequence of at most ~numberOfBytes~ bytes into the record from
the ~buffer~ provided by the user. Optionally a record ~offset~ can be
specified. The amount of bytes actually transfered is being returned.
*/
SmiSize Size();
void SetPos(SmiSize n) { pos = n; }
SmiSize GetPos() { return pos; }
/*
Retrieves the total amount of bytes stored within the persistent representation
of this record.
*/
SmiKey GetKey();
/*
Returns the key of this record.
*/
bool Truncate( const SmiSize newSize );
/*
Truncates the record to a specified length of ~newSize~ bytes.
The function returns "false"[4] if newSize is greater than the current record's
length.
*/
bool Resize(const SmiSize newSize);
/*
Resizes this Record. In constrast to the Truncate function also enlargements
od of the records are possible.
*/
SmiRecordId GetId() const{
SmiRecordId res;
recordKey.GetKey(res);
return res;
}
/*
Returns the record id of this record.
*/
void Finish();
/*
Finishes the operation on the associated record. The record handle may be
reused (i.e. reinitialized) afterwards. It is usually not necessary to call
this method when the record handle is not reused, since the destructor will
call it implicitly.
*NOTE*: If a transaction would end before the destructor is called it is
essential to explicitly call this method.
*/
protected:
private:
class Implementation;
Implementation* impl;
SmiFile* smiFile; // associated SmiFile object
SmiKey recordKey; // Key (or record no.) of this record
SmiSize recordSize; // Total size of the record
SmiSize pos; // current start position (offset)
bool fixedSize; // Record has fixed length
bool initialized; // Handle is initialized
bool writable; // Record is writable
friend class SmiFile;
friend class SmiFileIterator;
friend class SmiRecordFile;
friend class SmiRecordFileIterator;
friend class SmiKeyedFile;
friend class SmiKeyedFileIterator;
};
/**************************************************************************
1.3 Class "SmiRecordFile"[1]
The class ~SmiRecordFile~ allows record oriented access to persistent objects.
New records can only be appended to a ~SmiRecordFile~, but existing records can
be processed in random order using their record numbers.
By means of an iterator it is possible to scan through all records of a
~SmiFile~.
The records are obtained in the order they were appended to the file.
*/
class SmiRecordFileIterator; // Forward declaration
class SMI_EXPORT SmiRecordFile : public SmiCachedFile
{
public:
SmiRecordFile( const bool hasFixedLengthRecords,
const SmiSize recordLength = 0,
const bool isTemporary = false );
/*
Creates a handle for an ~SmiRecordFile~. The handle is associated with an
~SmiFile~ by means of the ~Create~ or ~Open~ method.
*/
~SmiRecordFile();
/*
Destroys a handle of an ~SmiRecordFile~.
*/
bool SelectRecord( const SmiRecordId recno,
SmiRecord& record,
const SmiFile::AccessType accessType =
SmiFile::ReadOnly );
/*
Selects the record identified by the record number ~recno~ for read only
or update access. The user has to provide a record handle which is
initialized by this method.
*/
bool Read(const SmiRecordId recno,
void* buffer,
const SmiSize length,
const SmiSize offset,
SmiSize& actSize);
/*
Reads data from a specified record. This will accelerate
operations if the record is only used local.
*/
bool Write(const SmiRecordId recno,
const void* buffer,
const SmiSize length,
const SmiSize offset,
SmiSize& written);
/*
Writes data to a specified record.
*/
char* GetData(const SmiRecordId recno,
SmiSize& length,
const bool dontReportError);
/*
Retrieves all data from the record selected by the RecordId.
The caller of that function is responsible for deleting the
returned data using free. length will return the size of the
returned data block. If that operation fails, for example because
the record id does not exist, the return value will be null.
*/
bool SelectAll( SmiRecordFileIterator& iterator,
const SmiFile::AccessType accessType =
SmiFile::ReadOnly);
/*
Initializes an iterator for sequentially accessing all records of the ~SmiFile~.
The requested access type - read only or update - has to be specified.
*/
PrefetchingIterator* SelectAllPrefetched();
/*
The same as ~SelectAll~, but returns a ~PrefetchingIterator~.
A ~PrefetchingIterator~ is read-only.
*/
bool AppendRecord( SmiRecordId& recno,
SmiRecord& record );
/*
Appends a new record to the ~SmiFile~ and returns a record handle pointing to
the new record.
*/
bool DeleteRecord( const SmiRecordId recno );
/*
Deletes the record identified by record number ~recno~ from the file.
*/
protected:
private:
};
/**************************************************************************
1.3 Class "SmiKeyedFile"[1]
The class ~SmiKeyedFile~ allows key oriented access to persistent objects.
Records are defined as key/data pairs. A key may have one of the types
Integer, Float, String or Composit. Data may have an arbitrary length.
By means of an iterator it is possible to scan through some or all records
of an ~SmiKeyedFile~. The records are retrieved in ascending order of the key
values. For duplicate records no special ordering is supported.
*/
struct SmiKeyRange {
SmiKeyRange() : less(0), equal(0), greater(0) {}
double less, equal, greater;
};
/*
A structure for storing proportional values of key ranges used in
method ~KeyRange~.
*/
class SmiKeyedFileIterator; // Forward declaration
class SMI_EXPORT SmiKeyedFile : public SmiCachedFile
{
public:
SmiKeyedFile( const SmiFile::FileType fileType,
const SmiKey::KeyDataType keyType,
const bool hasUniqueKeys,
const bool isTemporary );
/*
Creates a ~SmiFile~ handle for keyed access. The keys have to be of the
specified type ~keyType~. If ~hasUniqueKeys~ is true, then for each key
only one record can be stored. Otherwise duplicate records are allowed.
*/
virtual ~SmiKeyedFile() = 0;
/*
Destroys a file handle.
*/
SmiKey::KeyDataType GetKeyType() const;
/*
Returns the key type of the file.
*/
bool SelectRecord( const SmiKey& key,
SmiKeyedFileIterator& iterator,
const SmiFile::AccessType accessType =
SmiFile::ReadOnly );
/*
Selects the data record with the given key. It is required to specify
whether the select takes place for read only or update of the record.
This method always initializes a record iterator regardless whether
keys are unique or not. Usually this method should only be used when
duplicate records are supported.
The function returns "true"[4] when at least one record exists for
the given key.
*/
bool SelectRecord( const SmiKey& key,
SmiRecord& record,
const SmiFile::AccessType accessType =
SmiFile::ReadOnly );
/*
Selects the data record with the given key and initializes a ~SmiRecord~
handle for processing the record. In is required to specify whether the select
takes place for read only or update of the record. In case of
duplicates only the first record is returned with access type ~ReadOnly~,
regardless of the specified access type!
The function returns "true"[4] when a record exists for the given key.
*/
bool InsertRecord( const SmiKey& key, SmiRecord& record );
/*
Inserts a new record for the given key.
An ~SmiRecord~ handle is initialized on return to write the record.
The function returns "true"[4] when the record was created successfully.
*/
bool DeleteRecord( const SmiKey& key,
const bool all = true,
const SmiRecordId = 0 );
/*
Deletes all records having the given key.
The function returns "true"[4] when the records were successfully deleted.
*/
};
/**************************************************************************
1.3 Class "SmiHashFile"[1]
The class ~SmiHashFile~ uses hashing as access method for the ~SmiKeyedFile~.
It does not provide any method, since all its functionality is
implemented in the parent class.
*/
class SMI_EXPORT SmiHashFile : public SmiKeyedFile
{
public:
SmiHashFile( const SmiKey::KeyDataType keyType,
const bool hasUniqueKeys = true,
const bool isTemporary = false );
/*
Creates a ~SmiFile~ handle for keyed access using hashing as access method.
The keys have to be of the specified type ~keyType~. If ~hasUniqueKeys~ is
true, then for each key only one record can be stored. Otherwise duplicate
records are allowed.
*/
~SmiHashFile();
/*
Destroys a file handle.
*/
};
/**************************************************************************
1.3 Class "SmiBtreeFile"[1]
The class ~SmiBtreeFile~ uses B-Tree as access method for the
~SmiKeyedFile~. Additionally to the selection methods provided by
the parent class, it provides several range selection methods.
*/
class SMI_EXPORT SmiBtreeFile : public SmiKeyedFile
{
public:
SmiBtreeFile( const SmiKey::KeyDataType keyType,
const bool hasUniqueKeys = true,
const bool isTemporary = false );
/*
Creates a ~SmiFile~ handle for keyed access. The keys have to be of the
specified type ~keyType~. If ~hasUniqueKeys~ is true, then for each key
only one record can be stored. Otherwise duplicate records are allowed.
*/
~SmiBtreeFile();
/*
Destroys a file handle.
*/
bool KeyRange( const SmiKey& key, SmiKeyRange& range ) const;
/*
Returns three double values stored in the reference argument range,
between [0,1] which represent the proportion of all keys stored in
the file having a less, equal or greater key value than the given
key passed as first argument.
*/
bool SelectRange( const SmiKey& fromKey, const SmiKey& toKey,
SmiKeyedFileIterator& iterator,
const SmiFile::AccessType accessType =
SmiFile::ReadOnly,
const bool reportDuplicates = false );
/*
Selects a range of records with keys for which the following condition holds
"fromKey [<=] key [<=] toKey"[1]. A record iterator for processing the selected
records is initialized on return.
By default an iterator for read only access without reporting duplicates is
initialized, but update access and reporting of duplicates may be specified.
The function returns "true"[4] when the iterator was initialized successfully.
*/
PrefetchingIterator*
SelectRangePrefetched(const SmiKey& fromKey, const SmiKey& toKey);
/*
The same as ~SelectRange~, but returns a ~PrefetchingIterator~.
A ~PrefetchingIterator~ is read-only. Duplicates are always
reported.
*/
bool SelectLeftRange( const SmiKey& toKey,
SmiKeyedFileIterator& iterator,
const SmiFile::AccessType accessType =
SmiFile::ReadOnly,
const bool reportDuplicates = false );
/*
Selects a range of records with keys for which the following condition holds
"key [<=] toKey"[1]. A record iterator for processing the selected records
is initialized on return.
By default an iterator for read only access without reporting duplicates is
initialized, but update access and reporting of duplicates may be specified.
The function returns "true"[4] when the iterator was initialized successfully.
*/
PrefetchingIterator* SelectLeftRangePrefetched(const SmiKey& toKey);
/*
The same as ~SelectLeftRange~, but returns a ~PrefetchingIterator~.
A ~PrefetchingIterator~ is read-only. Duplicates are always
reported.
*/
bool SelectRightRange( const SmiKey& fromKey,
SmiKeyedFileIterator& iterator,
const SmiFile::AccessType accessType =
SmiFile::ReadOnly,
const bool reportDuplicates = false );
/*
Selects a range of records with keys for which the following condition holds
"fromKey [<=] key"[1]. A record iterator for processing the selected records
is initialized on return.
By default an iterator for read only access without reporting duplicates is
initialized, but update access and reporting of duplicates may be specified.
The function returns "true"[4] when the iterator was initialized successfully.
*/
PrefetchingIterator* SelectRightRangePrefetched(const SmiKey& fromKey);
/*
The same as ~SelectRightRange~, but returns a ~PrefetchingIterator~.
A ~PrefetchingIterator~ is read-only. Duplicates are always
reported.
*/
bool SelectAll( SmiKeyedFileIterator& iterator,
const SmiFile::AccessType accessType =
SmiFile::ReadOnly,
const bool reportDuplicates = false );
/*
Selects all records of the associated ~SmiBtreeFile~.
A record iterator for processing the selected records
is initialized on return.
By default an iterator for read only access without reporting duplicates is
initialized, but update access and reporting of duplicates may be specified.
The function returns "true"[4] when the iterator was initialized successfully.
*/
PrefetchingIterator* SelectAllPrefetched();
/*
The same as ~SelectAll~, but returns a ~PrefetchingIterator~.
A ~PrefetchingIterator~ is read-only. Duplicates are always
reported.
*/
protected:
private:
bool useTxn;
friend class PrefetchingIterator;
};
/**************************************************************************
1.3 Class "SmiFileIterator"[1]
The class ~SmiFileIterator~ allows to scan through all records of a
SmiFile. The order in which the records are retrieved depends on the type
of the ~SmiFile~. An ~SmiFileIterator~ is instantiated through an
~SmiRecordFileIterator~ or an ~SmiKeyedFileIterator~.
*/
class SMI_EXPORT SmiFileIterator
{
public:
bool DeleteCurrent();
/*
Deletes the current record.
*/
bool EndOfScan();
/*
Tells whether there are unscanned records left in the selected set of records.
*/
bool Finish();
/*
Closes the iterator. The iterator handle may be reused (i.e. reinitialized)
afterwards. This method should always be called as soon as access to the
record set selected by the iterator is not required anymore, although the
destructor will call it implicitly.
*/
bool Restart();
/*
Repositions the iterator in front of the first record of the selected set
of records.
*/
protected:
bool Next( SmiRecord& record );
/*
Advances the iterator to the next record of the selected set of records.
A handle to the current record is returned.
*NOTE*: This function is never called directly by the user, but by the
~Next~ function of a derived class, namely ~SmiRecordFileIterator~ and
~SmiKeyedFileIterator~.
*/
SmiFileIterator();
/*
Creates a handle for an ~SmiFile~ iterator. The handle is associated with an
~SmiFile~ by means of a ~Select~ method of that file. Initially the iterator is
positioned in front of the first record of the selected set of records.
*/
~SmiFileIterator();
/*
Destroys an ~SmiFile~ iterator handle.
*/
bool solelyDuplicates;
bool ignoreDuplicates;
/*
Flags whether duplicate records for a key may exist and whether those records
should be reported. If ~reportDuplicates~ is "false"[4], only the first
record of a set of duplicate records with equal keys is reported.
*/
SmiFile* smiFile; // associated SmiFile object
bool endOfScan; // Flag end of scan reached
bool opened; // Flag iterator opened
bool writable; // Flag iterator for update access
bool restart; // Flag for restart
bool rangeSearch; // Flag for range search using
SmiKey* searchKey; // Searchkey as start of range
class Implementation;
Implementation* impl;
private:
};
/**************************************************************************
1.3 Class "SmiRecordFileIterator"[1]
The class ~SmiRecordFileIterator~ allows to scan through all records of an
~SmiRecordFile~. The records are retrieved in the order as they were appended
to the file.
*/
class SMI_EXPORT SmiRecordFileIterator : public SmiFileIterator
{
public:
SmiRecordFileIterator();
/*
Creates a handle for an ~SmiRecordFile~ iterator. The handle is associated
with an ~SmiFile~ by means of a ~Select~ method of that file. Initially
the iterator is positioned in front of the first record of the selected
set of records.
*/
~SmiRecordFileIterator();
/*
Destroys an ~SmiRecordFileIterator~ handle.
*/
bool Next( SmiRecordId& recno, SmiRecord& record );
bool Next( SmiRecord& record );
/*
Advances the iterator to the next record of the selected set of records.
A handle to the current record and the record number of the
current record are returned.
*/
protected:
private:
friend class SmiRecordFile;
};
/**************************************************************************
1.3 Class "SmiKeyedFileIterator"[1]
The class ~SmiKeyedFileIterator~ allows to scan through some or all records
of an ~SmiKeyedFile~. The records are retrieved in ascending order according to
the associated key values.
*/
class SMI_EXPORT SmiKeyedFileIterator : public SmiFileIterator
{
public:
SmiKeyedFileIterator( bool reportDuplicates = false );
/*
Creates a handle for a ~SmiKeyedFile~ iterator. The handle is associated with a
~SmiFile~ by means of a ~Select~ method of that file. Initially the iterator is
positioned in front of the first record of the selected set of records.
*/
~SmiKeyedFileIterator();
/*
Destroys a ~SmiKeyedFile~ iterator handle.
*/
bool Next( SmiKey& key, SmiRecord& record );
bool Next( SmiRecord& record );
/*
Advances the iterator to the next record of the selected set of records.
A handle to the current record -- and the key of the current record, if
needed -- are returned.
*NOTE*: If the underlying ~SmiKeyedFile~ has keys of type ~SmiKey::Composite~ it
is *very important* to initialize the key object ~key~ with the correct key
mapping function, otherwise unmapping of the key does not take place. That
is ~key~ should be created as "SmiKey key( keyMappingFunction );"[4].
*/
protected:
private:
SmiKey firstKey; // Start of selected key range
SmiKey lastKey; // End of selected key range
friend class SmiKeyedFile;
friend class SmiBtreeFile;
};
/**************************************************************************
1.3 Class "PrefetchingIterator"[1]
The class ~PrefetchingIterator~ permits efficient read-only iteration over
an ~SmiKeyedFile~ or an ~SmiRecordFile~. The efficiency is achieved by
prefetching tuples.
Duplicates are supported and are always output.
*/
class PrefetchingIterator
{
protected:
SmiKey::KeyDataType keyType;
virtual void GetKeyAddressAndLength(void** addr, SmiSize& length) = 0;
/*
Returns the address and the length of the current key (represented as
a binary string). This method makes it possible that an implementation
of this interface need not be a friend of SmiKey, only this interface
itself needs to be a friend of SmiKey. This method is called by the
method ~CurrentKey~.
*/
public:
virtual ~PrefetchingIterator();
virtual void CurrentKey(SmiKey& smiKey);
/*
Returns the current key.
*/
virtual bool Next() = 0;
/*
Advances the iterator by one tuple. If the iterator cannot be advanced,
~false~ is returned.
*/
virtual SmiSize ReadCurrentData(void* userBuffer,
SmiSize nBytes, SmiSize offset = 0) = 0;
/*
This method is analogous to the ~Read~ method in ~SmiRecord~.
*/
virtual SmiSize ReadCurrentKey(void* userBuffer,
SmiSize nBytes, SmiSize offset = 0) = 0;
/*
This method is analogous to the ~Read~ method in ~SmiRecord~, however
it is not concerned with the data, but with the key of the current tuple.
This can only be called if the underlying file is an
~SmiKeyedFile~.
*/
virtual void ReadCurrentRecordNumber(SmiRecordId& recordNumber) = 0;
/*
Return the id of the current tuple. This can only be called if the
underlying file is an ~SmiRecordFile~.
*/
virtual int ErrorCode() = 0;
/*
Return the error code of the last failed database operation.
*/
};
#endif // SECONDO_SMI_H