1
// Spatial Index Library
3
// Copyright (C) 2002 Navel Ltd.
5
// This library is free software; you can redistribute it and/or
6
// modify it under the terms of the GNU Lesser General Public
7
// License as published by the Free Software Foundation; either
8
// version 2.1 of the License, or (at your option) any later version.
10
// This library is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
// Lesser General Public License for more details.
15
// You should have received a copy of the GNU Lesser General Public
16
// License along with this library; if not, write to the Free Software
17
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
#include "../spatialindex/SpatialIndexImpl.h"
26
#include <sys/types.h>
40
#define fsync(fd) _commit(fd)
43
#include "DiskStorageManager.h"
45
using namespace SpatialIndex;
46
using namespace SpatialIndex::StorageManager;
51
typedef SSIZE_T ssize_t;
54
SpatialIndex::IStorageManager* SpatialIndex::StorageManager::returnDiskStorageManager( Tools::PropertySet& ps )
56
IStorageManager* sm = new DiskStorageManager( ps );
60
SpatialIndex::IStorageManager* SpatialIndex::StorageManager::createNewDiskStorageManager( std::string& baseName, unsigned long pageSize )
63
Tools::PropertySet ps;
65
var.m_varType = Tools::VT_BOOL;
66
var.m_val.blVal = true;
67
ps.setProperty( "Overwrite", var );
68
// overwrite the file if it exists.
70
var.m_varType = Tools::VT_PCHAR;
71
var.m_val.pcVal = const_cast<char*>( baseName.c_str() );
72
ps.setProperty( "FileName", var );
73
// .idx and .dat extensions will be added.
75
var.m_varType = Tools::VT_ULONG;
76
var.m_val.ulVal = pageSize;
77
ps.setProperty( "PageSize", var );
78
// specify the page size. Since the index may also contain user defined data
79
// there is no way to know how big a single node may become. The storage manager
80
// will use multiple pages per node if needed. Off course this will slow down performance.
82
return returnDiskStorageManager( ps );
85
SpatialIndex::IStorageManager* SpatialIndex::StorageManager::loadDiskStorageManager( std::string& baseName )
88
Tools::PropertySet ps;
90
var.m_varType = Tools::VT_PCHAR;
91
var.m_val.pcVal = const_cast<char*>( baseName.c_str() );
92
ps.setProperty( "FileName", var );
93
// .idx and .dat extensions will be added.
95
return returnDiskStorageManager( ps );
98
DiskStorageManager::DiskStorageManager( Tools::PropertySet& ps ) : m_pageSize( 0 ), m_nextPage( -1 ), m_buffer( 0 )
103
bool bOverwrite = false;
104
var = ps.getProperty( "Overwrite" );
106
if ( var.m_varType != Tools::VT_EMPTY )
108
if ( var.m_varType != Tools::VT_BOOL ) throw Tools::IllegalArgumentException( "Property Overwrite must be Tools::VT_BOOL" );
109
bOverwrite = var.m_val.blVal;
113
var = ps.getProperty( "FileName" );
115
if ( var.m_varType != Tools::VT_EMPTY )
117
if ( var.m_varType != Tools::VT_PCHAR ) throw Tools::IllegalArgumentException( "Property FileName must be Tools::VT_PCHAR" );
119
int cLen = strlen( var.m_val.pcVal );
121
char* pIndexFile = new char[cLen + 10];
122
char* pDataFile = new char[cLen + 10];
124
sprintf( pIndexFile, "%s.idx", var.m_val.pcVal );
125
sprintf( pDataFile, "%s.dat", var.m_val.pcVal );
127
// check if file exists.
128
bool bFileExists = true;
129
int e1 = access( pIndexFile, F_OK );
130
int e2 = access( pDataFile, F_OK );
131
if ( e1 != 0 || e2 != 0 ) bFileExists = false;
133
if ( ! bFileExists ) bOverwrite = true;
135
// check if file can be read/written.
136
if ( bOverwrite == false )
138
int e1 = access( pIndexFile, R_OK | W_OK );
139
int e2 = access( pDataFile, R_OK | W_OK );
141
if (( e1 != 0 || e2 != 0 ) && bFileExists )
145
throw Tools::IllegalArgumentException( "Index file cannot be read/writen." );
149
int cMode = ( bOverwrite ) ? O_CREAT | O_RDWR | O_TRUNC : O_RDWR;
151
m_indexFile = open( pIndexFile, cMode, 0644 );
152
if ( m_indexFile < 0 )
156
throw Tools::IllegalArgumentException( "Index file cannot be opened." );
159
m_dataFile = open( pDataFile, cMode, 0644 );
160
if ( m_dataFile < 0 )
164
throw Tools::IllegalArgumentException( "Data file cannot be opened." );
172
throw Tools::IllegalArgumentException( "Property FileName was not specified." );
176
if ( bOverwrite == true )
178
var = ps.getProperty( "PageSize" );
180
if ( var.m_varType != Tools::VT_EMPTY )
182
if ( var.m_varType != Tools::VT_ULONG ) throw Tools::IllegalArgumentException( "Property PageSize must be Tools::VT_ULONG" );
183
m_pageSize = var.m_val.ulVal;
188
throw Tools::IllegalArgumentException( "A new storage manager is created and property PageSize was not specified." );
193
ssize_t bytesread = read( m_indexFile, &m_pageSize, sizeof( unsigned long ) );
194
if ( bytesread != sizeof( unsigned long ) ) throw Tools::IllegalStateException( "Failed reading pageSize." );
196
bytesread = read( m_indexFile, &m_nextPage, sizeof( long ) );
197
if ( bytesread != sizeof( long ) ) throw Tools::IllegalStateException( "Failed reading nextPage." );
201
m_buffer = new byte[m_pageSize];
202
memset( m_buffer, 0, m_pageSize );
204
if ( bOverwrite == false )
210
// load empty pages in memory.
211
bytesread = read( m_indexFile, &count, sizeof( unsigned long ) );
212
if ( bytesread != sizeof( unsigned long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
214
for ( unsigned long cCount = 0; cCount < count; cCount++ )
216
bytesread = read( m_indexFile, &page, sizeof( long ) );
217
if ( bytesread != sizeof( long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
218
m_emptyPages.push( page );
221
// load index table in memory.
222
bytesread = read( m_indexFile, &count, sizeof( unsigned long ) );
223
if ( bytesread != sizeof( unsigned long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
225
for ( unsigned long cCount = 0; cCount < count; cCount++ )
227
Entry* e = new Entry();
229
bytesread = read( m_indexFile, &id, sizeof( long ) );
230
if ( bytesread != sizeof( long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
232
bytesread = read( m_indexFile, &( e->m_length ), sizeof( unsigned long ) );
233
if ( bytesread != sizeof( unsigned long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
235
unsigned long count2;
236
bytesread = read( m_indexFile, &count2, sizeof( unsigned long ) );
237
if ( bytesread != sizeof( unsigned long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
239
for ( unsigned long cCount2 = 0; cCount2 < count2; cCount2++ )
241
bytesread = read( m_indexFile, &page, sizeof( long ) );
242
if ( bytesread != sizeof( long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
243
e->m_pages.push_back( page );
245
m_pageIndex.insert( std::pair<long, Entry* >( id, e ) );
250
DiskStorageManager::~DiskStorageManager()
253
close( m_indexFile );
255
if ( m_buffer != 0 ) delete[] m_buffer;
257
map<long, Entry*>::iterator it = m_pageIndex.begin();
259
while ( it != m_pageIndex.end() )
261
delete( *it ).second;
266
void DiskStorageManager::flush()
268
ssize_t byteswritten;
270
off_t seek = lseek( m_indexFile, 0, SEEK_SET );
271
if ( seek < 0 ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
273
byteswritten = write( m_indexFile, &m_pageSize, sizeof( unsigned long ) );
274
if ( byteswritten != sizeof( unsigned long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
275
byteswritten = write( m_indexFile, &m_nextPage, sizeof( long ) );
276
if ( byteswritten != sizeof( long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
278
unsigned long count = m_emptyPages.size();
281
byteswritten = write( m_indexFile, &count, sizeof( unsigned long ) );
282
if ( byteswritten != sizeof( unsigned long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
284
while ( ! m_emptyPages.empty() )
286
page = m_emptyPages.top(); m_emptyPages.pop();
287
byteswritten = write( m_indexFile, &page, sizeof( long ) );
288
if ( byteswritten != sizeof( long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
291
count = m_pageIndex.size();
293
byteswritten = write( m_indexFile, &count, sizeof( unsigned long ) );
294
if ( byteswritten != sizeof( unsigned long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
296
map<long, Entry*>::iterator it = m_pageIndex.begin();
298
while ( it != m_pageIndex.end() )
301
byteswritten = write( m_indexFile, &id, sizeof( long ) );
302
if ( byteswritten != sizeof( long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
304
count = ( *it ).second->m_length;
305
byteswritten = write( m_indexFile, &count, sizeof( long ) );
306
if ( byteswritten != sizeof( long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
308
count = ( *it ).second->m_pages.size();
309
byteswritten = write( m_indexFile, &count, sizeof( long ) );
310
if ( byteswritten != sizeof( long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
312
for ( unsigned long cIndex = 0; cIndex < count; cIndex++ )
314
page = ( *it ).second->m_pages[cIndex];
315
byteswritten = write( m_indexFile, &page, sizeof( long ) );
316
if ( byteswritten != sizeof( long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
321
fsync( m_indexFile );
325
void DiskStorageManager::loadByteArray( const long id, unsigned long& len, byte** data )
327
map<long, Entry*>::iterator it = m_pageIndex.find( id );
329
if ( it == m_pageIndex.end() ) throw Tools::InvalidPageException( id );
331
vector<long>& pages = ( *it ).second->m_pages;
332
unsigned long cNext = 0;
333
unsigned long cTotal = pages.size();
335
len = ( *it ).second->m_length;
336
*data = new byte[len];
340
unsigned long cRem = len;
344
off_t seek = lseek( m_dataFile, pages[cNext] * m_pageSize, SEEK_SET );
345
if ( seek < 0 ) throw Tools::IllegalStateException( "Corrupted data file." );
347
ssize_t bytesread = read( m_dataFile, m_buffer, m_pageSize );
348
if ( bytesread <= 0 ) throw Tools::IllegalStateException( "Corrupted data file." );
350
cLen = ( cRem > m_pageSize ) ? m_pageSize : cRem;
351
memcpy( ptr, m_buffer, cLen );
357
while ( cNext < cTotal );
360
void DiskStorageManager::storeByteArray( long& id, const unsigned long len, const byte* const data )
364
Entry* e = new Entry();
367
const byte* ptr = data;
369
unsigned long cRem = len;
374
if ( ! m_emptyPages.empty() )
376
cPage = m_emptyPages.top(); m_emptyPages.pop();
384
cLen = ( cRem > m_pageSize ) ? m_pageSize : cRem;
385
memcpy( m_buffer, ptr, cLen );
387
off_t seek = lseek( m_dataFile, cPage * m_pageSize, SEEK_SET );
388
if ( seek < 0 ) throw Tools::IllegalStateException( "Corrupted data file." );
389
ssize_t byteswritten = write( m_dataFile, m_buffer, m_pageSize );
390
if ( byteswritten <= 0 ) throw Tools::IllegalStateException( "Corrupted data file." );
394
e->m_pages.push_back( cPage );
398
m_pageIndex.insert( std::pair<long, Entry*>( id, e ) );
403
map<long, Entry*>::iterator it = m_pageIndex.find( id );
405
// check if it exists.
406
if ( it == m_pageIndex.end() ) throw Tools::IndexOutOfBoundsException( id );
408
Entry* oldEntry = ( *it ).second;
410
m_pageIndex.erase( it );
412
Entry* e = new Entry();
415
const byte* ptr = data;
417
unsigned long cRem = len;
418
unsigned long cLen, cNext = 0;
422
if ( cNext < oldEntry->m_pages.size() )
424
cPage = oldEntry->m_pages[cNext];
427
else if ( ! m_emptyPages.empty() )
429
cPage = m_emptyPages.top(); m_emptyPages.pop();
437
cLen = ( cRem > m_pageSize ) ? m_pageSize : cRem;
438
memcpy( m_buffer, ptr, cLen );
440
off_t seek = lseek( m_dataFile, cPage * m_pageSize, SEEK_SET );
441
if ( seek < 0 ) throw Tools::IllegalStateException( "Corrupted data file." );
442
ssize_t byteswritten = write( m_dataFile, m_buffer, m_pageSize );
443
if ( byteswritten <= 0 ) throw Tools::IllegalStateException( "Corrupted data file." );
447
e->m_pages.push_back( cPage );
450
while ( cNext < oldEntry->m_pages.size() )
452
m_emptyPages.push( oldEntry->m_pages[cNext] );
456
m_pageIndex.insert( std::pair<long, Entry*>( id, e ) );
461
void DiskStorageManager::deleteByteArray( const long id )
463
map<long, Entry*>::iterator it = m_pageIndex.find( id );
465
if ( it == m_pageIndex.end() ) throw Tools::InvalidPageException( id );
467
for ( unsigned long cIndex = 0; cIndex < ( *it ).second->m_pages.size(); cIndex++ )
469
m_emptyPages.push(( *it ).second->m_pages[cIndex] );
472
delete( *it ).second;
473
m_pageIndex.erase( it );