Skip to content

Commit f36f925

Browse files
committed
Disallow using Fullname SerialDC with mutiple ranks in write-mode
Add tests for that
1 parent 6f1c0cd commit f36f925

5 files changed

Lines changed: 279 additions & 14 deletions

File tree

src/SerialDataCollector.cpp

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,17 @@ namespace splash
6969
return (stat(filename.c_str(), &fileInfo) == 0);
7070
}
7171

72-
std::string SerialDataCollector::getFullFilename(const Dimensions mpiPos, std::string baseFilename) const
72+
std::string SerialDataCollector::getFullFilename(const Dimensions mpiPos, std::string baseFilename,
73+
bool isFullNameAllowed) const throw (DCException)
7374
{
7475
// Check for existing extension
7576
if (baseFilename.find(".h5") == baseFilename.length() - 3)
76-
return baseFilename;
77+
{
78+
if (isFullNameAllowed)
79+
return baseFilename;
80+
else
81+
throw DCException("Full filename is not allowed!");
82+
}
7783

7884
std::stringstream serial_filename;
7985
serial_filename << baseFilename << "_" << mpiPos[0] << "_" << mpiPos[1] <<
@@ -166,14 +172,14 @@ namespace splash
166172

167173
log_msg(1, "closing serial data collector");
168174

169-
if (fileStatus == FST_CREATING || fileStatus == FST_WRITING)
175+
if ((fileStatus == FST_CREATING || fileStatus == FST_WRITING) &&
176+
maxID >= 0)
170177
{
171-
DCGroup group;
172-
group.open(handles.get(0), SDC_GROUP_HEADER);
173-
174178
// write number of iterations
175179
try
176180
{
181+
DCGroup group;
182+
group.open(handles.get(0), SDC_GROUP_HEADER);
177183
ColTypeInt32 ctInt32;
178184
DCAttribute::writeAttribute(SDC_ATTR_MAX_ID, ctInt32.getDataType(),
179185
group.getHandle(), &maxID);
@@ -753,7 +759,8 @@ namespace splash
753759
{
754760
this->fileStatus = FST_CREATING;
755761

756-
std::string full_filename = getFullFilename(attr.mpiPosition, filename);
762+
std::string full_filename = getFullFilename(attr.mpiPosition, filename,
763+
attr.mpiSize.getScalarSize() == 1);
757764

758765
this->enableCompression = attr.enableCompression;
759766

@@ -784,7 +791,8 @@ namespace splash
784791
{
785792
fileStatus = FST_WRITING;
786793

787-
std::string full_filename = getFullFilename(attr.mpiPosition, filename);
794+
std::string full_filename = getFullFilename(attr.mpiPosition, filename,
795+
attr.mpiSize.getScalarSize() == 1);
788796

789797
this->enableCompression = attr.enableCompression;
790798

@@ -806,7 +814,7 @@ namespace splash
806814
this->fileStatus = FST_MERGING;
807815

808816
// open reference file to get mpi information
809-
std::string full_filename = getFullFilename(Dimensions(0, 0, 0), filename);
817+
std::string full_filename = getFullFilename(Dimensions(0, 0, 0), filename, true);
810818

811819
if (!fileExists(full_filename))
812820
{
@@ -829,7 +837,7 @@ namespace splash
829837
{
830838
this->fileStatus = FST_READING;
831839

832-
std::string full_filename = getFullFilename(attr.mpiPosition, filename);
840+
std::string full_filename = getFullFilename(attr.mpiPosition, filename, true);
833841

834842
if (!fileExists(full_filename))
835843
{

src/include/splash/SerialDataCollector.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,15 @@ namespace splash
6262
* Constructs a filename from a base filename and the process' mpi position
6363
* such as myfile_0_1_0.h5
6464
* Does nothing if the filename already ends with ".h5" (only allowed
65-
* for Prod(mpiSize)==1).
65+
* for Prod(mpiSize)==1 or reading).
6666
*
6767
* @param mpiPos MPI position of the process
6868
* @param baseFilename base filename for the new file
69+
* @param isFullNameAllowed If false, an exception is raised when a full name is passed
6970
* @return newly constructed filename including file extension
7071
*/
71-
std::string getFullFilename(const Dimensions mpiPos, std::string baseFilename) const;
72+
std::string getFullFilename(const Dimensions mpiPos, std::string baseFilename,
73+
bool isFullNameAllowed) const throw (DCException);
7274

7375
/**
7476
* Internal function for formatting exception messages.

tests/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,15 @@ IF(WITH_MPI)
6767
SET(TESTS ${TESTS} Benchmark Domains)
6868
ENDIF(WITH_MPI)
6969

70-
OPTION(PARALLEL "enable tests for parallel libSplash" @HDF5_IS_PARALLEL@)
70+
OPTION(PARALLEL "enable tests for parallel libSplash" ${HDF5_IS_PARALLEL})
7171
IF(PARALLEL)
7272
IF(NOT WITH_MPI)
7373
# MPI is required package
7474
FIND_PACKAGE(MPI REQUIRED)
7575
INCLUDE_DIRECTORIES(${MPI_C_INCLUDE_PATH} ${MPI_CXX_INCLUDE_PATH})
7676
ENDIF(NOT WITH_MPI)
7777

78-
SET(TESTS ${TESTS} Parallel_Attributes Parallel_Filename Parallel_Domains Parallel_ListFiles Parallel_References Parallel_Remove Parallel_SimpleData Parallel_ZeroAccess)
78+
SET(TESTS ${TESTS} Parallel_Attributes Parallel_Filename Parallel_Domains Parallel_ListFiles Parallel_References Parallel_Remove Parallel_SerialDC Parallel_SimpleData Parallel_ZeroAccess)
7979
ELSE(PARALLEL)
8080
SET(TESTS ${TESTS})
8181
ENDIF(PARALLEL)

tests/Parallel_SerialDCTest.cpp

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
/**
2+
* Copyright 2016 Alexander Grund
3+
*
4+
* This file is part of libSplash.
5+
*
6+
* libSplash is free software: you can redistribute it and/or modify
7+
* it under the terms of of either the GNU General Public License or
8+
* the GNU Lesser General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* libSplash is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License and the GNU Lesser General Public License
16+
* for more details.
17+
*
18+
* You should have received a copy of the GNU General Public License
19+
* and the GNU Lesser General Public License along with libSplash.
20+
* If not, see <http://www.gnu.org/licenses/>.
21+
*/
22+
23+
#include <cppunit/extensions/HelperMacros.h>
24+
25+
#include "splash/splash.h"
26+
#include <mpi.h>
27+
#include <unistd.h>
28+
#include <sys/stat.h>
29+
30+
using namespace splash;
31+
32+
class FilenameTest : public CPPUNIT_NS::TestFixture
33+
{
34+
CPPUNIT_TEST_SUITE(FilenameTest);
35+
36+
CPPUNIT_TEST(testBaseName);
37+
CPPUNIT_TEST(testFullName);
38+
39+
CPPUNIT_TEST_SUITE_END();
40+
41+
public:
42+
43+
FilenameTest();
44+
virtual ~FilenameTest();
45+
46+
private:
47+
/**
48+
* Tests that file naming is correct when passing only base name
49+
*/
50+
void testBaseName();
51+
52+
/**
53+
* Tests that file naming is correct when passing full name
54+
*/
55+
void testFullName();
56+
57+
bool fileExists(const std::string& filename);
58+
59+
DataCollector *dataCollector;
60+
ColTypeInt ctInt;
61+
int mpiRank;
62+
static int initCt;
63+
};
64+
65+
int FilenameTest::initCt = 0;
66+
67+
CPPUNIT_TEST_SUITE_REGISTRATION(FilenameTest);
68+
69+
#define HDF5_FILE "h5/testParallelSerialDC"
70+
#define HDF5_BASE_FILE HDF5_FILE "_0_0_0.h5"
71+
#define HDF5_FULL_FILE HDF5_FILE "Full.h5"
72+
73+
#define MPI_SIZE_X 4
74+
#define MPI_SIZE_Y 2
75+
76+
FilenameTest::FilenameTest()
77+
{
78+
if(!initCt)
79+
{
80+
MPI_Init(NULL, NULL);
81+
srand(time(NULL));
82+
// Remove old files
83+
unlink(HDF5_BASE_FILE);
84+
unlink(HDF5_FULL_FILE);
85+
}
86+
initCt++;
87+
88+
int mpiSize;
89+
MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
90+
MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
91+
92+
CPPUNIT_ASSERT(mpiSize == (MPI_SIZE_X * MPI_SIZE_Y));
93+
94+
dataCollector = new SerialDataCollector(10);
95+
}
96+
97+
FilenameTest::~FilenameTest()
98+
{
99+
if (dataCollector)
100+
{
101+
delete dataCollector;
102+
dataCollector = NULL;
103+
}
104+
if(!--initCt)
105+
MPI_Finalize();
106+
}
107+
108+
bool FilenameTest::fileExists(const std::string& filename)
109+
{
110+
struct stat fileInfo;
111+
return (stat(filename.c_str(), &fileInfo) == 0);
112+
}
113+
114+
void FilenameTest::testBaseName()
115+
{
116+
// MPI rank should be appended
117+
CPPUNIT_ASSERT(!fileExists(HDF5_BASE_FILE));
118+
119+
// Wait till all checked the above
120+
MPI_Barrier(MPI_COMM_WORLD);
121+
122+
DataCollector::FileCreationAttr attr;
123+
DataCollector::initFileCreationAttr(attr);
124+
attr.fileAccType = DataCollector::FAT_CREATE;
125+
attr.mpiSize = Dimensions(MPI_SIZE_X, MPI_SIZE_Y, 1);
126+
attr.mpiPosition = Dimensions(mpiRank % MPI_SIZE_X, mpiRank / MPI_SIZE_X, 0);
127+
128+
// write first dataset to file (create file)
129+
dataCollector->open(HDF5_FILE, attr);
130+
int data1 = rand();
131+
132+
dataCollector->write(2, ctInt, 1, Selection(Dimensions(1, 1, 1)), "data1", &data1);
133+
dataCollector->close();
134+
135+
// Now file must exist
136+
CPPUNIT_ASSERT(fileExists(HDF5_BASE_FILE));
137+
138+
// write second dataset to file (write to existing file of same name
139+
attr.fileAccType = DataCollector::FAT_WRITE;
140+
dataCollector->open(HDF5_FILE, attr);
141+
int data2 = rand();
142+
143+
dataCollector->write(2, ctInt, 1, Selection(Dimensions(1, 1, 1)), "data2", &data2);
144+
dataCollector->close();
145+
146+
147+
// read data from file
148+
attr.fileAccType = DataCollector::FAT_READ;
149+
Dimensions data_size;
150+
151+
int data = -1;
152+
dataCollector->open(HDF5_FILE, attr);
153+
154+
dataCollector->read(2, "data1", data_size, &data);
155+
156+
CPPUNIT_ASSERT(data_size.getScalarSize() == 1);
157+
CPPUNIT_ASSERT(data == data1);
158+
159+
dataCollector->read(2, "data2", data_size, &data);
160+
161+
CPPUNIT_ASSERT(data_size.getScalarSize() == 1);
162+
CPPUNIT_ASSERT(data == data2);
163+
164+
dataCollector->close();
165+
166+
// erase file
167+
attr.fileAccType = DataCollector::FAT_CREATE;
168+
dataCollector->open(HDF5_FILE, attr);
169+
170+
CPPUNIT_ASSERT_THROW(dataCollector->read(2, "data1", data_size, &data), DCException);
171+
int data3 = rand();
172+
dataCollector->write(2, ctInt, 1, Selection(Dimensions(1, 1, 1)), "data1", &data3);
173+
dataCollector->close();
174+
175+
176+
data = -1;
177+
// Read from created file
178+
attr.fileAccType = DataCollector::FAT_READ;
179+
dataCollector->open(HDF5_FILE, attr);
180+
181+
dataCollector->read(2, "data1", data_size, &data);
182+
183+
CPPUNIT_ASSERT(data_size.getScalarSize() == 1);
184+
CPPUNIT_ASSERT(data == data3);
185+
dataCollector->close();
186+
}
187+
188+
void FilenameTest::testFullName()
189+
{
190+
// MPI rank should be appended
191+
CPPUNIT_ASSERT(!fileExists(HDF5_FULL_FILE));
192+
193+
// Wait till all checked the above
194+
MPI_Barrier(MPI_COMM_WORLD);
195+
196+
DataCollector::FileCreationAttr attr;
197+
DataCollector::initFileCreationAttr(attr);
198+
attr.fileAccType = DataCollector::FAT_CREATE;
199+
attr.mpiSize = Dimensions(MPI_SIZE_X, MPI_SIZE_Y, 1);
200+
attr.mpiPosition = Dimensions(mpiRank % MPI_SIZE_X, mpiRank / MPI_SIZE_X, 0);
201+
202+
CPPUNIT_ASSERT_THROW(dataCollector->open(HDF5_FULL_FILE, attr), DCException);
203+
dataCollector->close();
204+
attr.fileAccType = DataCollector::FAT_WRITE;
205+
CPPUNIT_ASSERT_THROW(dataCollector->open(HDF5_FULL_FILE, attr), DCException);
206+
dataCollector->close();
207+
208+
int data1, data2;
209+
if (mpiRank == 0)
210+
{
211+
attr.fileAccType = DataCollector::FAT_CREATE;
212+
attr.mpiSize = Dimensions(1, 1, 1);
213+
dataCollector->open(HDF5_FULL_FILE, attr);
214+
data1 = rand();
215+
216+
dataCollector->write(2, ctInt, 1, Selection(Dimensions(1, 1, 1)), "data1", &data1);
217+
dataCollector->close();
218+
219+
// Now file must exist
220+
CPPUNIT_ASSERT(fileExists(HDF5_FULL_FILE));
221+
222+
// write second dataset to file (write to existing file of same name
223+
attr.fileAccType = DataCollector::FAT_WRITE;
224+
dataCollector->open(HDF5_FULL_FILE, attr);
225+
data2 = rand();
226+
227+
dataCollector->write(2, ctInt, 1, Selection(Dimensions(1, 1, 1)), "data2", &data2);
228+
dataCollector->close();
229+
attr.mpiSize = Dimensions(MPI_SIZE_X, MPI_SIZE_Y, 1);
230+
}
231+
MPI_Bcast(&data1, 1, MPI_INT, 0, MPI_COMM_WORLD);
232+
MPI_Bcast(&data2, 1, MPI_INT, 0, MPI_COMM_WORLD);
233+
234+
// read data from file
235+
attr.fileAccType = DataCollector::FAT_READ;
236+
Dimensions data_size;
237+
238+
int data = -1;
239+
dataCollector->open(HDF5_FULL_FILE, attr);
240+
241+
dataCollector->read(2, "data1", data_size, &data);
242+
243+
CPPUNIT_ASSERT(data_size.getScalarSize() == 1);
244+
CPPUNIT_ASSERT(data == data1);
245+
246+
dataCollector->read(2, "data2", data_size, &data);
247+
248+
CPPUNIT_ASSERT(data_size.getScalarSize() == 1);
249+
CPPUNIT_ASSERT(data == data2);
250+
251+
dataCollector->close();
252+
}
253+

tests/run_parallel_tests

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ function testMPI()
5555
testMPI ./Parallel_SimpleDataTest.cpp.out 8 "Testing simple data read/write (parallel)..."
5656
testMPI ./Parallel_FilenameTest.cpp.out 1 "Testing file naming (parallel)..."
5757

58+
testMPI ./Parallel_SerialDC.cpp.out 8 "Testing SerialDataCollector (parallel)..."
59+
5860
testMPI ./Parallel_ListFilesTest.cpp.out 1 "Testing list files (parallel)..."
5961

6062
testMPI ./Parallel_DomainsTest.cpp.out 8 "Testing domains (parallel)..."

0 commit comments

Comments
 (0)