diff --git a/CMakeLists.txt b/CMakeLists.txt index 32f61aff8de..e8690e93449 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,7 @@ cmake_minimum_required (VERSION 2.6.0) include(CheckCXXCompilerFlag) include(CheckCCompilerFlag) include(CheckFunctionExists) +include(CheckCXXSourceCompiles) # fixes warnings on cmake 3.x+ For now we want the old behavior to be backwards compatible if (POLICY CMP0048) @@ -50,6 +51,15 @@ option (ENABLE_SHARED "Build shared libraries" YES) option (ENABLE_RPATH "Include rpath in executables and shared libraries" YES) +# Check if O_DIRECT is available. +# Note this does not work well with check_c_source_compiles. +check_cxx_source_compiles(" + #include + main() { int i = O_DIRECT; } + " HAVE_O_DIRECT) +if (HAVE_O_DIRECT) + add_definitions(-DHAVE_O_DIRECT) +endif() # By default do not use ADIOS2, HDF5, FFTW3 option (ENABLE_TABLELOCKING "Make locking for concurrent table access possible" YES) @@ -537,6 +547,7 @@ message (STATUS "USE_THREADS ........... = ${USE_THREADS}") message (STATUS "USE_OPENMP ............ = ${USE_OPENMP}") message (STATUS "USE_MPI ............... = ${USE_MPI}") message (STATUS "USE_STACKTRACE ........ = ${USE_STACKTRACE}") +message (STATUS "HAVE_O_DIRECT ......... = ${HAVE_O_DIRECT}") message (STATUS "CMAKE_CXX_COMPILER .... = ${CMAKE_CXX_COMPILER}") message (STATUS "CMAKE_CXX_FLAGS ....... = ${CMAKE_CXX_FLAGS}") message (STATUS "DATA directory ........ = ${DATA_DIR}") diff --git a/casa/IO/MultiFile.cc b/casa/IO/MultiFile.cc index 3bdf45d6b96..c609bd68c41 100644 --- a/casa/IO/MultiFile.cc +++ b/casa/IO/MultiFile.cc @@ -41,10 +41,10 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN MultiFile::MultiFile (const String& name, ByteIO::OpenOption option, - Int blockSize) - : MultiFileBase (name, blockSize) + Int blockSize, Bool useODirect) + : MultiFileBase (name, blockSize, useODirect) { - itsFD = RegularFileIO::openCreate (itsName, option); + itsFD = RegularFileIO::openCreate (itsName, option, itsUseODirect); itsIO.attach (itsFD, itsName); if (option == ByteIO::New || option == ByteIO::NewNoReplace) { // New file; first block is for administration. @@ -78,7 +78,7 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN return; } // First try if the file can be opened as read/write. - int fd = RegularFileIO::openCreate (itsName, ByteIO::Update); + int fd = RegularFileIO::openCreate (itsName, ByteIO::Update, itsUseODirect); // Now close the readonly file and reset fd. FiledesIO::close (itsFD); itsIO.detach(); @@ -112,8 +112,15 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN uChar* buf = const_cast(mio.getBuffer()); CanonicalConversion::fromLocal (buf, todo); // header size // Write the first part of the buffer at the beginning of the file. + // Use an aligned buffer for possible O_DIRECT alignment. itsIO.seek (0); - itsIO.write (itsBlockSize, buf); + if (itsUseODirect) { + MultiFileBuffer mfbuf(itsBlockSize, itsUseODirect); + memcpy (mfbuf.data, buf, itsBlockSize); + itsIO.pwrite (itsBlockSize, 0, mfbuf.data); + } else { + itsIO.pwrite (itsBlockSize, 0, buf); + } todo -= itsBlockSize; if (todo > 0) { // The rest is written in another file. If the header info was written @@ -168,7 +175,7 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN iter!=itsInfo.end(); ++iter) { iter->curBlock = -1; iter->dirty = False; - iter->buffer.resize (itsBlockSize); + iter->allocBuffer (itsBlockSize, itsUseODirect); } } @@ -207,8 +214,7 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN void MultiFile::readBlock (MultiFileInfo& info, Int64 blknr, void* buffer) { - itsIO.pread (itsBlockSize, info.blockNrs[blknr] * - itsBlockSize, buffer); + itsIO.pread (itsBlockSize, info.blockNrs[blknr] * itsBlockSize, buffer); } void MultiFile::writeBlock (MultiFileInfo& info, Int64 blknr, diff --git a/casa/IO/MultiFile.h b/casa/IO/MultiFile.h index a5a29ad7189..d1ad15197f4 100644 --- a/casa/IO/MultiFile.h +++ b/casa/IO/MultiFile.h @@ -52,12 +52,14 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN // reduce the number of open files (especially when concatenating tables). //
A secondary goal is offering the ability to use an IO buffer size // that matches the file system well (large buffer size for e.g. ZFS). + //
A third goal is offering the ability to use O_DIRECT (if supported by OS) + // to tell the OS kernel to bypass its file cache. It makes the I/O behaviour + // more predictable which a real-time system might need. // // The SetupNewTable constructor has a StorageOption argument to define // if a MultiFile has to be used and if so, the buffer size to use. // It is also possible to specify that through aipsrc variables. // - // A virtual file is spread over multiple (fixed size) data blocks in the // MultiFile. A data block is never shared by multiple files. // For each virtual file MultiFile keeps a MultiFileInfo object telling @@ -111,7 +113,10 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN // Open or create a MultiFile with the given name. // Upon creation the block size can be given. If 0, it uses the block size // of the file system the file is on. - MultiFile (const String& name, ByteIO::OpenOption, Int blockSize=0); + // If useODirect=True, the O_DIRECT flag in used (if supported). It tells the + // kernel to bypass its file cache to have more predictable I/O behaviour. + MultiFile (const String& name, ByteIO::OpenOption, Int blockSize=0, + Bool useODirect=False); // The destructor flushes and closes the file. virtual ~MultiFile(); diff --git a/casa/IO/MultiFileBase.cc b/casa/IO/MultiFileBase.cc index eed36f3bace..a8ebdb4a2e9 100644 --- a/casa/IO/MultiFileBase.cc +++ b/casa/IO/MultiFileBase.cc @@ -31,9 +31,10 @@ #include #include #include -#include // for fileFSTAT +#include // for fileSTAT #include // needed for stat or stat64 #include +#include // for posix_memalign namespace casacore { //# NAMESPACE CASACORE - BEGIN @@ -46,12 +47,18 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN { ios >> info.name >> info.blockNrs >> info.fsize; } - MultiFileBase::MultiFileBase (const String& name, Int blockSize) + MultiFileBase::MultiFileBase (const String& name, Int blockSize, Bool useODirect) : itsBlockSize (blockSize), itsNrBlock (0), itsHdrCounter (0), + itsUseODirect (useODirect), + itsWritable (False), // usually reset by derived class itsChanged (False) { + // Unset itsUseODirect if the OS does not support it. +#ifndef HAVE_O_DIRECT + itsUseODirect = False; +#endif itsName = Path(name).expandedName(); } @@ -111,6 +118,7 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN } char* buffer = static_cast(buf); MultiFileInfo& info = itsInfo[fileId]; + char* infoBuffer = info.buffer->data; // Determine the logical block to read and the start offset in that block. Int64 nrblk = (info.fsize + itsBlockSize - 1) / itsBlockSize; Int64 blknr = offset/itsBlockSize; @@ -123,19 +131,19 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN Int64 todo = std::min(szdo-done, itsBlockSize-start); // If already in buffer, copy from there. if (blknr == info.curBlock) { - memcpy (buffer, &(info.buffer[start]), todo); + memcpy (buffer, infoBuffer+start, todo); } else { - // Read directly into buffer if it fits exactly. - if (todo == itsBlockSize) { + // Read directly into buffer if it fits exactly and no O_DIRECT. + if (todo == itsBlockSize && !itsUseODirect) { readBlock (info, blknr, buffer); } else { if (info.dirty) { writeDirty (info); } // Read into file buffer and copy correct part. - readBlock (info, blknr, &(info.buffer[0])); + readBlock (info, blknr, infoBuffer); info.curBlock = blknr; - memcpy (buffer, &(info.buffer[start]), todo); + memcpy (buffer, infoBuffer+start, todo); } } // Increment counters. @@ -156,6 +164,7 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN const char* buffer = static_cast(buf); AlwaysAssert (itsWritable, AipsError); MultiFileInfo& info = itsInfo[fileId]; + char* infoBuffer = info.buffer->data; // Determine the logical block to write and the start offset in that block. Int64 blknr = offset/itsBlockSize; Int64 start = offset - blknr*itsBlockSize; @@ -172,13 +181,13 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN Int64 todo = std::min(size-done, itsBlockSize-start); // Favor sequential writing, thus write current buffer first. if (blknr == info.curBlock) { - memcpy (&(info.buffer[start]), buffer, todo); + memcpy (infoBuffer+start, buffer, todo); info.dirty = True; if (done+todo > size) { writeDirty (info); } - } else if (todo == itsBlockSize) { - // Write directly from buffer if it fits exactly. + } else if (todo == itsBlockSize && !itsUseODirect) { + // Write directly from buffer if it fits exactly and no O_DIRECT. writeBlock (info, blknr, buffer); } else { // Write into temporary buffer and copy correct part. @@ -187,12 +196,12 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN writeDirty (info); } if (blknr >= curnrb) { - memset (&(info.buffer[0]), 0, itsBlockSize); + memset (infoBuffer, 0, itsBlockSize); } else { - readBlock (info, blknr, &(info.buffer[0])); + readBlock (info, blknr, infoBuffer); } info.curBlock = blknr; - memcpy (&(info.buffer[start]), buffer, todo); + memcpy (infoBuffer+start, buffer, todo); info.dirty = True; } done += todo; @@ -242,7 +251,7 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN if (inx == itsInfo.size()) { itsInfo.resize (inx+1); } - itsInfo[inx] = MultiFileInfo(itsBlockSize); + itsInfo[inx] = MultiFileInfo(itsBlockSize, itsUseODirect); itsInfo[inx].name = bname; doAddFile (itsInfo[inx]); itsChanged = True; @@ -278,13 +287,44 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN } - - MultiFileInfo::MultiFileInfo (Int64 bufSize) + MultiFileInfo::MultiFileInfo (Int64 bufSize, Bool useODirect) : curBlock (-1), fsize (0), - dirty (False) + dirty (False), + buffer (new MultiFileBuffer (bufSize, useODirect)) + {} + + + MultiFileBuffer::MultiFileBuffer (size_t bufSize, Bool useODirect) + : data (0) { - buffer.resize (bufSize); + const size_t align = 4096; + // Free buffer (in case used). + if (data) { + free (data); + data = 0; + } + if (bufSize > 0) { + if (useODirect && bufSize%align != 0) { + throw AipsError("MultiFile bufsize " + String::toString(bufSize) + + " must be a multiple of 4096 when using O_DIRECT"); + } + // Note that the error messages do a malloc as well, but small + // compared to the requested malloc, so they'll probably succeed. + void* ptr; + if (useODirect) { + if (posix_memalign (&ptr, align, bufSize) != 0) { + throw AllocError("MultiFileBuffer: failed to allocate aligned buffer", + bufSize); + } + } else { + ptr = malloc (bufSize); + if (!ptr) { + throw AllocError("MultiFileBuffer: failed to allocate buffer", bufSize); + } + } + data = static_cast(ptr); + } } diff --git a/casa/IO/MultiFileBase.h b/casa/IO/MultiFileBase.h index 11d1f3056ac..4ccb9c69365 100644 --- a/casa/IO/MultiFileBase.h +++ b/casa/IO/MultiFileBase.h @@ -46,17 +46,47 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN // - // Helper class for MultiFileBase containing info per internal file + // Helper class for MultiFileInfo holding a data buffer // + // + // The buffer can be allocated with posix_memalign (for O_DIRECT support). + // Hence the memory must be freed using free, which makes it impossible + // to use a shared_ptr to that memory. Hence it is encapsulated in this class. + // + struct MultiFileBuffer { + MultiFileBuffer (size_t bufSize, Bool useODirect); + ~MultiFileBuffer() + { if (data) free (data); } + // Data member + char* data; + private: + MultiFileBuffer (const MultiFileBuffer&); + MultiFileBuffer& operator= (const MultiFileBuffer&); + }; + + // + // Helper class for MultiFileBase containing info per internal file. + // + // + // This struct defines the various fields describing a logical file in a + // class derived from MultiFileBase (such as MultiFile or MultiHDF5). + // // struct MultiFileInfo { - explicit MultiFileInfo (Int64 bufSize=0); + // Initialize the object and create the buffer with the proper size. + // If align>1 (for use of O_DIRECT), the buffer is properly aligned and it + // is ensured that its size is a multiple of the alignment. + explicit MultiFileInfo (Int64 bufSize=0, Bool useODirect=False); + // Allocate the buffer. + void allocBuffer (Int64 bufSize, Bool useODirect=False) + { buffer = std::shared_ptr (new MultiFileBuffer(bufSize, useODirect)); } + //# Data members. vector blockNrs; // physical blocknrs for this logical file - vector buffer; // buffer holding a data block Int64 curBlock; // the data block held in buffer (<0 is none) Int64 fsize; // file size (in bytes) String name; // the virtual file name Bool dirty; // has data in buffer been changed? + std::shared_ptr buffer; // buffer holding a data block CountedPtr group; CountedPtr dataSet; }; @@ -137,7 +167,10 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN // Open or create a MultiFileBase with the given name. // Upon creation the block size can be given. If 0, it uses the block size // of the file system the file is on. - MultiFileBase (const String& name, Int blockSize=0); + // If useODIrect=True, it means that O_DIRECT is used. If the OS does not + // support it, the flag will always be False. If True, the data buffers will + // have a proper alignment and size (as needed by O_DIRECT). + MultiFileBase (const String& name, Int blockSize, Bool useODirect); // The destructor flushes and closes the file. virtual ~MultiFileBase(); @@ -185,6 +218,10 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN Bool isWritable() const { return itsWritable; } + // Will O_DIRECT be used? + Bool useODirect() const + { return itsUseODirect; } + // Get the block size used. Int64 blockSize() const { return itsBlockSize; } @@ -207,7 +244,7 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN private: void writeDirty (MultiFileInfo& info) { - writeBlock (info, info.curBlock, &(info.buffer[0])); + writeBlock (info, info.curBlock, info.buffer->data); info.dirty = False; } @@ -243,8 +280,10 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN Int64 itsNrBlock; // The total nr of blocks actually used Int64 itsHdrCounter; // Counter of header changes vector itsInfo; - Bool itsWritable; // Is the file writable? - Bool itsChanged; // Has header info changed since last flush? + std::shared_ptr itsBuffer; + Bool itsUseODirect; // use O_DIRECT? + Bool itsWritable; // Is the file writable? + Bool itsChanged; // Has header info changed since last flush? vector itsFreeBlocks; }; diff --git a/casa/IO/MultiHDF5.cc b/casa/IO/MultiHDF5.cc index 8f79f446078..b252559cfcd 100644 --- a/casa/IO/MultiHDF5.cc +++ b/casa/IO/MultiHDF5.cc @@ -36,7 +36,7 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN MultiHDF5::MultiHDF5 (const String& name, ByteIO::OpenOption option, Int blockSize) - : MultiFileBase (name, blockSize), + : MultiFileBase (name, blockSize, False), //# no O_DIRECT in HDF5 itsFile (itsName, option) { if (option == ByteIO::New || option == ByteIO::NewNoReplace) { diff --git a/casa/IO/RegularFileIO.cc b/casa/IO/RegularFileIO.cc index bba5ca571aa..ac22fbf1449 100644 --- a/casa/IO/RegularFileIO.cc +++ b/casa/IO/RegularFileIO.cc @@ -61,7 +61,8 @@ RegularFileIO::~RegularFileIO() } int RegularFileIO::openCreate (const RegularFile& file, - ByteIO::OpenOption option) + ByteIO::OpenOption option, + Bool useODirect) { const String& name = file.path().expandedName(); Bool create = False; @@ -90,16 +91,31 @@ int RegularFileIO::openCreate (const RegularFile& file, default: throw (AipsError ("RegularFileIO: unknown open option")); } - // Open the file. + Int stropt_orig = stropt; +#ifdef HAVE_O_DIRECT + if (useODirect) { + stropt |= O_DIRECT; + } +#else + useODirect = False; +#endif + // Open the file. Try it twice in case O_DIRECT fails. int fd; - if (create) { - fd = trace3OPEN ((char*)name.chars(), stropt, 0666); - } else { - fd = trace2OPEN ((char*)name.chars(), stropt); + for (int i=0; i<2; ++i) { + if (create) { + fd = trace3OPEN ((char*)name.chars(), stropt, 0666); + } else { + fd = trace2OPEN ((char*)name.chars(), stropt); + } + if (fd < 0 && useODirect) { + stropt = stropt_orig; + } else { + break; + } } if (fd < 0) { - throw (AipsError ("RegularFileIO: error in open or create of file " + - name + ": " + strerror(errno))); + throw (AipsError ("RegularFileIO: error in open or create of file " + + name + ": " + strerror(errno))); } return fd; } diff --git a/casa/IO/RegularFileIO.h b/casa/IO/RegularFileIO.h index 8f59afce0c3..63e7206ee1c 100644 --- a/casa/IO/RegularFileIO.h +++ b/casa/IO/RegularFileIO.h @@ -105,8 +105,13 @@ class RegularFileIO: public FilebufIO // Convenience function to open or create a file. // Optionally it is checked if the file does not exist yet. + // If useODirect=True and if supported by the OS, the file will be opened + // with O_DIRECT which bypasses the kernel's file cache for more predictable + // I/O behaviour. It requires the size and the alignment of the data to be + // read/written to be a multiple of the the disk's logival block size. // It returns the file descriptor. - static int openCreate (const RegularFile& file, ByteIO::OpenOption); + static int openCreate (const RegularFile& file, ByteIO::OpenOption, + Bool useODirect=False); private: OpenOption itsOption; diff --git a/casa/IO/test/tMultiFile.cc b/casa/IO/test/tMultiFile.cc index 13fc0214042..edb7650cc9b 100644 --- a/casa/IO/test/tMultiFile.cc +++ b/casa/IO/test/tMultiFile.cc @@ -48,9 +48,9 @@ void showMultiFile (MultiFile& mfile) << mfile.freeBlocks() << endl; } -void makeFile (Int64 blockSize) +void makeFile (Int64 blockSize, Bool useODirect) { - MultiFile mfile("tMultiFile_tmp.dat", ByteIO::New, blockSize); + MultiFile mfile("tMultiFile_tmp.dat", ByteIO::New, blockSize, useODirect); AlwaysAssertExit (mfile.isWritable()); showMultiFile(mfile); } @@ -254,10 +254,10 @@ void timeMove3() timer.show ("move3 "); } -void doTest (Int64 blockSize) +void doTest (Int64 blockSize, Bool useODirect=False) { cout << "MultiFile test with blockSize=" << blockSize << endl; - makeFile (blockSize); + makeFile (blockSize, useODirect); readFile(); addFiles(); readFile(); @@ -274,8 +274,9 @@ void doTest (Int64 blockSize) int main() { try { - doTest (128); // requires extra header file - doTest (1024); // no extra header file + doTest (128); // requires extra header file + doTest (1024); // no extra header file + doTest (4096, True); // with O_DIRECT (if possible) timeExact(); timeDouble(); timePartly(); diff --git a/tables/Tables/ColumnSet.cc b/tables/Tables/ColumnSet.cc index 2d7ff489be0..e14908a2bf8 100644 --- a/tables/Tables/ColumnSet.cc +++ b/tables/Tables/ColumnSet.cc @@ -191,7 +191,8 @@ void ColumnSet::openMultiFile (uInt from, const Table& tab, if (! multiFile_p) { if (storageOpt_p.option() == StorageOption::MultiFile) { multiFile_p = new MultiFile (tab.tableName() + "/table.mf", - opt, storageOpt_p.blockSize()); + opt, storageOpt_p.blockSize(), + storageOpt_p.useODirect()); } else { multiFile_p = new MultiHDF5 (tab.tableName() + "/table.mfh5", opt, storageOpt_p.blockSize()); diff --git a/tables/Tables/StorageOption.cc b/tables/Tables/StorageOption.cc index a414ab7495c..fc0a260aaca 100644 --- a/tables/Tables/StorageOption.cc +++ b/tables/Tables/StorageOption.cc @@ -30,9 +30,12 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN - StorageOption::StorageOption (StorageOption::Option option, Int blockSize) - : itsOption (option), - itsBlockSize (blockSize) + StorageOption::StorageOption (StorageOption::Option option, Int blockSize, + Int useODirect) + : itsOption (option), + itsBlockSize (blockSize), + itsUseODirect (useODirect>0), + itsUseAipsrcODirect (useODirect<0) {} void StorageOption::fillOption() @@ -59,10 +62,20 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN if (itsBlockSize <= 0) { itsBlockSize = 4*1024*1024; } + // Default O_DIRECT support is False. + if (itsUseAipsrcODirect) { + AipsrcValue::find (itsUseODirect, "table.storage.odirect", False); + } // Default is to use separate files. if (itsOption == StorageOption::Default) { itsOption = StorageOption::SepFile; } } + void StorageOption::setUseODirect (Bool useODirect) + { + itsUseODirect = useODirect; + itsUseAipsrcODirect = False; + } + } //# NAMESPACE CASACORE - END diff --git a/tables/Tables/StorageOption.h b/tables/Tables/StorageOption.h index 238a5444226..a42e8dec644 100644 --- a/tables/Tables/StorageOption.h +++ b/tables/Tables/StorageOption.h @@ -54,7 +54,8 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN //
The block size to be used in a MultiFile can be defined in // this class. Default is 4 MByte. //
  • Using MultiHDF5 which behaves similar to MultiFile but uses an -// HDF5 file instead of a regular file. +// HDF5 file instead of a regular file. Note that it requires that +// support for HDF5 has been used in the build system. // // It is possible to specify the storage type and block size using aipsrc. // The aipsrc variables are: @@ -64,6 +65,10 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN // Another value means the old way (separate files). //
  • table.storage.blocksize gives the default blocksize to be // used for the multifile and multihdf5 option. +//
  • table.storage.odirect can be true or false. It tells if the +// O_DIRECT option has to be used to let the kernel bypass its filecache +// for more predictable I/O behaviour. It's only used for MultiFile and +// only if the OS supports O_DIRECT. // // @@ -79,7 +84,7 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN MultiHDF5, // Let storage managers use separate files. SepFile, - // Use default (currently MultiFile). + // Use default (currently SepFile). Default, // Use as defined in the aipsrc file. Aipsrc @@ -90,7 +95,9 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN // The blocksize has to be given in bytes. // A size value -2 means reading that size from the aipsrc file. // A size value -1 means use the default of 4*1024*1024. - StorageOption (Option option=Aipsrc, Int blockSize=-2); + //
    useODirect<0 means reading the option from the aipsrc file. + // It is only set if the OS supports O_DIRECT. + StorageOption (Option option=Aipsrc, Int blockSize=-2, Int useODirect=-3); // Fill the option in case Aipsrc or Default was given. // It is done as explained in the synopsis. @@ -112,9 +119,19 @@ namespace casacore { //# NAMESPACE CASACORE - BEGIN void setBlockSize (Int blockSize) { itsBlockSize = blockSize; } + // Get the O_DIRECT option. + Bool useODirect() const + { return itsUseODirect; } + + // Set the O_DIRECT option. + // It is only set if the OS supports O_DIRECT. + void setUseODirect (Bool useODirect); + private: Option itsOption; Int itsBlockSize; + Bool itsUseODirect; + Bool itsUseAipsrcODirect; }; } //# NAMESPACE CASACORE - END diff --git a/tables/Tables/test/tTable.cc b/tables/Tables/test/tTable.cc index f8dcf753e3a..38e12f92eda 100644 --- a/tables/Tables/test/tTable.cc +++ b/tables/Tables/test/tTable.cc @@ -89,7 +89,7 @@ Table::EndianFormat theEndianFormat = Table::BigEndian; // First build a description. -void a (Bool doExcp) +void a (const StorageOption& stopt, Bool doExcp) { // Build the table description. TableDesc td("", "1", TableDesc::Scratch); @@ -105,7 +105,7 @@ void a (Bool doExcp) // Now create a new table from the description. // Use copy constructor to test if it works fine. // (newtab and newtabcp have the same underlying object). - SetupNewTable newtab("tTable_tmp.data", td, Table::New); + SetupNewTable newtab("tTable_tmp.data", td, Table::New, stopt); SetupNewTable newtabcp(newtab); // Create a storage manager for it. StManAipsIO sm1; @@ -578,7 +578,7 @@ void b (Bool doExcp) } //# Test deletion of rows, array of Strings, and some more. -void c (Bool doExcp) +void c (const StorageOption& stopt, Bool doExcp) { TableDesc td("", "1", TableDesc::Scratch); td.addColumn (ScalarColumnDesc("ab","Comment for column ab")); @@ -592,7 +592,7 @@ void c (Bool doExcp) td.addColumn (ArrayColumnDesc("arr3",0,ColumnDesc::Direct)); // Now create a new table from the description. - SetupNewTable newtab("tTable_tmp.data1", td, Table::New); + SetupNewTable newtab("tTable_tmp.data1", td, Table::New, stopt); // Create a storage manager for it. StManAipsIO sm1; StManAipsIO sm2; @@ -751,7 +751,7 @@ void c (Bool doExcp) } -void d() +void d (const StorageOption& stopt) { Vector arrf2(100); indgen (arrf2); @@ -766,7 +766,7 @@ void d() td.addColumn (ArrayColumnDesc ("arr3",0,ColumnDesc::Direct)); // Now create a new table from the description. - SetupNewTable newtab("tTable_tmp.data3", td, Table::New); + SetupNewTable newtab("tTable_tmp.data3", td, Table::New, stopt); // Create a storage manager for it. StManAipsIO sm1; newtab.bindAll (sm1); @@ -913,10 +913,18 @@ int main (int argc,const char*[]) { try { Table::setScratchCallback (cbFunc); - a ( (argc<2)); + StorageOption stopt; + a ( stopt, (argc<2)); b ( (argc<2)); - c ( (argc<2)); - d (); + c ( stopt, (argc<2)); + d ( stopt); + // Also test with MultiFile (with O_DIRECT if supported). + cout< +datatypes arr2 = float Array +datatypes arr3 = float Array +get scalar row 0 +get array row 0 +get scalar row 1 +get array row 1 +get scalar row 2 +get array row 2 +get scalar row 3 +get array row 3 +get scalar row 4 +get array row 4 +get scalar row 5 +get array row 5 +get scalar row 6 +get array row 6 +get scalar row 7 +get array row 7 +get scalar row 8 +get array row 8 +get scalar row 9 +get array row 9 +10 10 +[12, 11, 10, 9, 8, 7, 6, 5, 4, 3] +#columns in sortab: 9 +[2, 3, 4, 5, 6, 7, 8, 9, 10, 11] +#columns in sortab2: 9 +sortab2 type = testtype +sortab2 subtype = testsubtype +first readme line +second test readme line +a sortab line + +[9, 6, 3, 1] +[9, 6, 3, 1] +[0, 3, 6, 8] +[6, 8, 0, 3] +#columns in seltab1: 9 +[6, 8, 0, 3] +#columns in seltab2: 3 +[8, 0] +#columns in seltab3: 3 + +TableDesc version 1 (Directory **SCRATCH**) +--------- + Comment: A test of class Table + #Keywords = 0 + #Columns = 3 + Name=ae DataType=float + DataManager=StandardStMan/StandardStMan Default=0 + Comment = + #keywords=0 + + Name=ab DataType=Int + DataManager=StandardStMan/StandardStMan Default=0 + Comment = Comment for column ab + #keywords=0 + + Name=arr1 DataType=float Nrdim=3 Shape=[2, 3, 4] + DataManager=StandardStMan/StandardStMan + Comment = + #keywords=0 + +[1, 2, 4, 5, 7, 9] +#columns in xortab: 9 +[0, 1, 2, 4, 5, 7, 8, 9] +#columns in or1tab: 9 +[0, 1, 2, 4, 5, 7, 8, 9] +#columns in or2tab: 3 +[9, 8, 7, 6, 5] +[3, 5, 6, 7] +[6, 7, 8, 9] +>>> +ScratchCallBack: name=tab17115_20 isScratch=0 oldName= +<<< +ScratchCallBack: name=tTable_tmp.ex1 isScratch=1 oldName= +ScratchCallBack: name=tTable_tmp.ex1 isScratch=0 oldName= +ScratchCallBack: name=tTable_tmp.data1 isScratch=1 oldName= +ScratchCallBack: name=tTable_tmp.data1 isScratch=0 oldName= +ScratchCallBack: name=tTable_tmp.data2 isScratch=1 oldName= +ScratchCallBack: name=tTable_tmp.data2a isScratch=1 oldName=tTable_tmp.data2 +ScratchCallBack: name=tTable_tmp.data2a isScratch=0 oldName= +ScratchCallBack: name=tTable_tmp.data2 isScratch=1 oldName= +ScratchCallBack: name=tTable_tmp.data2 isScratch=0 oldName= +Expected exception: Table tTable_tmp.file already exists (and is not a true table directory) +Expected exception: Table tTable_tmp.data already exists +Expected exception: Table tTable.datx does not exist +Expected exception: Invalid description of column ab: column already exists +[3, 5, 6, 7] +[3, 6] +[0, 1, 2, 4, 5, 7, 8, 9] +Expected exception: Invalid Table operation: removeRow: rownr 7 too high in table tTable_tmp.data2a (#rows=7) +[0, 1, 2, 4, 5, 7, 8] +[0, 1] +[23, 4] +[5, 6] +[9, 100] +[1, 2] +[6, 7] +[8, 9] +Axis Lengths: [2, 7] (NB: Matrix in Row/Column order) +[0, 23, 5, 9, 1, 6, 8 + 1, 4, 6, 100, 2, 7, 9] + +ScratchCallBack: name=tTable_tmp.data3 isScratch=1 oldName= +ScratchCallBack: name=tTable_tmp.data3 isScratch=0 oldName=