~ubuntu-branches/ubuntu/wily/qgis/wily

« back to all changes in this revision

Viewing changes to src/core/spatialindex/storagemanager/DiskStorageManager.cc

  • Committer: Bazaar Package Importer
  • Author(s): Johan Van de Wauw
  • Date: 2010-07-11 20:23:24 UTC
  • mfrom: (3.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100711202324-5ktghxa7hracohmr
Tags: 1.4.0+12730-3ubuntu1
* Merge from Debian unstable (LP: #540941).
* Fix compilation issues with QT 4.7
* Add build-depends on libqt4-webkit-dev 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Spatial Index Library
 
2
//
 
3
// Copyright (C) 2002 Navel Ltd.
 
4
//
 
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.
 
9
//
 
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.
 
14
//
 
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
 
18
//
 
19
//  Email:
 
20
//    mhadji@gmail.com
 
21
 
 
22
#include "../spatialindex/SpatialIndexImpl.h"
 
23
 
 
24
#include <unistd.h>
 
25
#include <fcntl.h>
 
26
#include <sys/types.h>
 
27
#include <sys/stat.h>
 
28
#include <stdio.h>
 
29
#include <cstring>
 
30
 
 
31
#ifdef WIN32
 
32
#include <io.h>
 
33
#ifdef _MSC_VER
 
34
#include <basetsd.h>
 
35
#define F_OK 0
 
36
#define X_OK 1
 
37
#define W_OK 2
 
38
#define R_OK 4
 
39
#endif//_MSC_VER
 
40
#define fsync(fd) _commit(fd)
 
41
#endif
 
42
 
 
43
#include "DiskStorageManager.h"
 
44
 
 
45
using namespace SpatialIndex;
 
46
using namespace SpatialIndex::StorageManager;
 
47
using std::map;
 
48
using std::vector;
 
49
 
 
50
#ifdef _MSC_VER
 
51
typedef SSIZE_T ssize_t;
 
52
#endif//_MSC_VER
 
53
 
 
54
SpatialIndex::IStorageManager* SpatialIndex::StorageManager::returnDiskStorageManager( Tools::PropertySet& ps )
 
55
{
 
56
  IStorageManager* sm = new DiskStorageManager( ps );
 
57
  return sm;
 
58
}
 
59
 
 
60
SpatialIndex::IStorageManager* SpatialIndex::StorageManager::createNewDiskStorageManager( std::string& baseName, unsigned long pageSize )
 
61
{
 
62
  Tools::Variant var;
 
63
  Tools::PropertySet ps;
 
64
 
 
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.
 
69
 
 
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.
 
74
 
 
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.
 
81
 
 
82
  return returnDiskStorageManager( ps );
 
83
}
 
84
 
 
85
SpatialIndex::IStorageManager* SpatialIndex::StorageManager::loadDiskStorageManager( std::string& baseName )
 
86
{
 
87
  Tools::Variant var;
 
88
  Tools::PropertySet ps;
 
89
 
 
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.
 
94
 
 
95
  return returnDiskStorageManager( ps );
 
96
}
 
97
 
 
98
DiskStorageManager::DiskStorageManager( Tools::PropertySet& ps ) : m_pageSize( 0 ), m_nextPage( -1 ), m_buffer( 0 )
 
99
{
 
100
  Tools::Variant var;
 
101
 
 
102
  // Open/Create flag.
 
103
  bool bOverwrite = false;
 
104
  var = ps.getProperty( "Overwrite" );
 
105
 
 
106
  if ( var.m_varType != Tools::VT_EMPTY )
 
107
  {
 
108
    if ( var.m_varType != Tools::VT_BOOL ) throw Tools::IllegalArgumentException( "Property Overwrite must be Tools::VT_BOOL" );
 
109
    bOverwrite = var.m_val.blVal;
 
110
  }
 
111
 
 
112
  // storage filename.
 
113
  var = ps.getProperty( "FileName" );
 
114
 
 
115
  if ( var.m_varType != Tools::VT_EMPTY )
 
116
  {
 
117
    if ( var.m_varType != Tools::VT_PCHAR ) throw Tools::IllegalArgumentException( "Property FileName must be Tools::VT_PCHAR" );
 
118
 
 
119
    int cLen = strlen( var.m_val.pcVal );
 
120
 
 
121
    char* pIndexFile = new char[cLen + 10];
 
122
    char* pDataFile = new char[cLen + 10];
 
123
 
 
124
    sprintf( pIndexFile, "%s.idx", var.m_val.pcVal );
 
125
    sprintf( pDataFile, "%s.dat", var.m_val.pcVal );
 
126
 
 
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;
 
132
 
 
133
    if ( ! bFileExists ) bOverwrite = true;
 
134
 
 
135
    // check if file can be read/written.
 
136
    if ( bOverwrite == false )
 
137
    {
 
138
      int e1 = access( pIndexFile, R_OK | W_OK );
 
139
      int e2 = access( pDataFile, R_OK | W_OK );
 
140
 
 
141
      if (( e1 != 0 || e2 != 0 ) && bFileExists )
 
142
      {
 
143
        delete[] pIndexFile;
 
144
        delete[] pDataFile;
 
145
        throw Tools::IllegalArgumentException( "Index file cannot be read/writen." );
 
146
      }
 
147
    }
 
148
 
 
149
    int cMode = ( bOverwrite ) ? O_CREAT | O_RDWR | O_TRUNC : O_RDWR;
 
150
 
 
151
    m_indexFile = open( pIndexFile, cMode, 0644 );
 
152
    if ( m_indexFile < 0 )
 
153
    {
 
154
      delete[] pIndexFile;
 
155
      delete[] pDataFile;
 
156
      throw Tools::IllegalArgumentException( "Index file cannot be opened." );
 
157
    }
 
158
 
 
159
    m_dataFile = open( pDataFile, cMode, 0644 );
 
160
    if ( m_dataFile < 0 )
 
161
    {
 
162
      delete[] pIndexFile;
 
163
      delete[] pDataFile;
 
164
      throw Tools::IllegalArgumentException( "Data file cannot be opened." );
 
165
    }
 
166
 
 
167
    delete[] pIndexFile;
 
168
    delete[] pDataFile;
 
169
  }
 
170
  else
 
171
  {
 
172
    throw Tools::IllegalArgumentException( "Property FileName was not specified." );
 
173
  }
 
174
 
 
175
  // find page size.
 
176
  if ( bOverwrite == true )
 
177
  {
 
178
    var = ps.getProperty( "PageSize" );
 
179
 
 
180
    if ( var.m_varType != Tools::VT_EMPTY )
 
181
    {
 
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;
 
184
      m_nextPage = 0;
 
185
    }
 
186
    else
 
187
    {
 
188
      throw Tools::IllegalArgumentException( "A new storage manager is created and property PageSize was not specified." );
 
189
    }
 
190
  }
 
191
  else
 
192
  {
 
193
    ssize_t bytesread = read( m_indexFile, &m_pageSize, sizeof( unsigned long ) );
 
194
    if ( bytesread != sizeof( unsigned long ) ) throw Tools::IllegalStateException( "Failed reading pageSize." );
 
195
 
 
196
    bytesread = read( m_indexFile, &m_nextPage, sizeof( long ) );
 
197
    if ( bytesread != sizeof( long ) ) throw Tools::IllegalStateException( "Failed reading nextPage." );
 
198
  }
 
199
 
 
200
  // create buffer.
 
201
  m_buffer = new byte[m_pageSize];
 
202
  memset( m_buffer, 0, m_pageSize );
 
203
 
 
204
  if ( bOverwrite == false )
 
205
  {
 
206
    unsigned long count;
 
207
    long id, page;
 
208
    ssize_t bytesread;
 
209
 
 
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." );
 
213
 
 
214
    for ( unsigned long cCount = 0; cCount < count; cCount++ )
 
215
    {
 
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 );
 
219
    }
 
220
 
 
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." );
 
224
 
 
225
    for ( unsigned long cCount = 0; cCount < count; cCount++ )
 
226
    {
 
227
      Entry* e = new Entry();
 
228
 
 
229
      bytesread = read( m_indexFile, &id, sizeof( long ) );
 
230
      if ( bytesread != sizeof( long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
 
231
 
 
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." );
 
234
 
 
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." );
 
238
 
 
239
      for ( unsigned long cCount2 = 0; cCount2 < count2; cCount2++ )
 
240
      {
 
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 );
 
244
      }
 
245
      m_pageIndex.insert( std::pair<long, Entry* >( id, e ) );
 
246
    }
 
247
  }
 
248
}
 
249
 
 
250
DiskStorageManager::~DiskStorageManager()
 
251
{
 
252
  flush();
 
253
  close( m_indexFile );
 
254
  close( m_dataFile );
 
255
  if ( m_buffer != 0 ) delete[] m_buffer;
 
256
 
 
257
  map<long, Entry*>::iterator it = m_pageIndex.begin();
 
258
 
 
259
  while ( it != m_pageIndex.end() )
 
260
  {
 
261
    delete( *it ).second;
 
262
    it++;
 
263
  }
 
264
}
 
265
 
 
266
void DiskStorageManager::flush()
 
267
{
 
268
  ssize_t byteswritten;
 
269
 
 
270
  off_t seek = lseek( m_indexFile, 0, SEEK_SET );
 
271
  if ( seek < 0 ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
 
272
 
 
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." );
 
277
 
 
278
  unsigned long count = m_emptyPages.size();
 
279
  long id, page;
 
280
 
 
281
  byteswritten = write( m_indexFile, &count, sizeof( unsigned long ) );
 
282
  if ( byteswritten != sizeof( unsigned long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
 
283
 
 
284
  while ( ! m_emptyPages.empty() )
 
285
  {
 
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." );
 
289
  }
 
290
 
 
291
  count = m_pageIndex.size();
 
292
 
 
293
  byteswritten = write( m_indexFile, &count, sizeof( unsigned long ) );
 
294
  if ( byteswritten != sizeof( unsigned long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
 
295
 
 
296
  map<long, Entry*>::iterator it = m_pageIndex.begin();
 
297
 
 
298
  while ( it != m_pageIndex.end() )
 
299
  {
 
300
    id = ( *it ).first;
 
301
    byteswritten = write( m_indexFile, &id, sizeof( long ) );
 
302
    if ( byteswritten != sizeof( long ) ) throw Tools::IllegalStateException( "Corrupted storage manager index file." );
 
303
 
 
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." );
 
307
 
 
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." );
 
311
 
 
312
    for ( unsigned long cIndex = 0; cIndex < count; cIndex++ )
 
313
    {
 
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." );
 
317
    }
 
318
    it++;
 
319
  }
 
320
 
 
321
  fsync( m_indexFile );
 
322
  fsync( m_dataFile );
 
323
}
 
324
 
 
325
void DiskStorageManager::loadByteArray( const long id, unsigned long& len, byte** data )
 
326
{
 
327
  map<long, Entry*>::iterator it = m_pageIndex.find( id );
 
328
 
 
329
  if ( it == m_pageIndex.end() ) throw Tools::InvalidPageException( id );
 
330
 
 
331
  vector<long>& pages = ( *it ).second->m_pages;
 
332
  unsigned long cNext = 0;
 
333
  unsigned long cTotal = pages.size();
 
334
 
 
335
  len = ( *it ).second->m_length;
 
336
  *data = new byte[len];
 
337
 
 
338
  byte* ptr = *data;
 
339
  unsigned long cLen;
 
340
  unsigned long cRem = len;
 
341
 
 
342
  do
 
343
  {
 
344
    off_t seek = lseek( m_dataFile, pages[cNext] * m_pageSize, SEEK_SET );
 
345
    if ( seek < 0 ) throw Tools::IllegalStateException( "Corrupted data file." );
 
346
 
 
347
    ssize_t bytesread = read( m_dataFile, m_buffer, m_pageSize );
 
348
    if ( bytesread <= 0 ) throw Tools::IllegalStateException( "Corrupted data file." );
 
349
 
 
350
    cLen = ( cRem > m_pageSize ) ? m_pageSize : cRem;
 
351
    memcpy( ptr, m_buffer, cLen );
 
352
 
 
353
    ptr += cLen;
 
354
    cRem -= cLen;
 
355
    cNext++;
 
356
  }
 
357
  while ( cNext < cTotal );
 
358
}
 
359
 
 
360
void DiskStorageManager::storeByteArray( long& id, const unsigned long len, const byte* const data )
 
361
{
 
362
  if ( id == NewPage )
 
363
  {
 
364
    Entry* e = new Entry();
 
365
    e->m_length = len;
 
366
 
 
367
    const byte* ptr = data;
 
368
    long cPage;
 
369
    unsigned long cRem = len;
 
370
    unsigned long cLen;
 
371
 
 
372
    while ( cRem > 0 )
 
373
    {
 
374
      if ( ! m_emptyPages.empty() )
 
375
      {
 
376
        cPage = m_emptyPages.top(); m_emptyPages.pop();
 
377
      }
 
378
      else
 
379
      {
 
380
        cPage = m_nextPage;
 
381
        m_nextPage++;
 
382
      }
 
383
 
 
384
      cLen = ( cRem > m_pageSize ) ? m_pageSize : cRem;
 
385
      memcpy( m_buffer, ptr, cLen );
 
386
 
 
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." );
 
391
 
 
392
      ptr += cLen;
 
393
      cRem -= cLen;
 
394
      e->m_pages.push_back( cPage );
 
395
    }
 
396
 
 
397
    id = e->m_pages[0];
 
398
    m_pageIndex.insert( std::pair<long, Entry*>( id, e ) );
 
399
  }
 
400
  else
 
401
  {
 
402
    // find the entry.
 
403
    map<long, Entry*>::iterator it = m_pageIndex.find( id );
 
404
 
 
405
    // check if it exists.
 
406
    if ( it == m_pageIndex.end() ) throw Tools::IndexOutOfBoundsException( id );
 
407
 
 
408
    Entry* oldEntry = ( *it ).second;
 
409
 
 
410
    m_pageIndex.erase( it );
 
411
 
 
412
    Entry* e = new Entry();
 
413
    e->m_length = len;
 
414
 
 
415
    const byte* ptr = data;
 
416
    long cPage;
 
417
    unsigned long cRem = len;
 
418
    unsigned long cLen, cNext = 0;
 
419
 
 
420
    while ( cRem > 0 )
 
421
    {
 
422
      if ( cNext < oldEntry->m_pages.size() )
 
423
      {
 
424
        cPage = oldEntry->m_pages[cNext];
 
425
        cNext++;
 
426
      }
 
427
      else if ( ! m_emptyPages.empty() )
 
428
      {
 
429
        cPage = m_emptyPages.top(); m_emptyPages.pop();
 
430
      }
 
431
      else
 
432
      {
 
433
        cPage = m_nextPage;
 
434
        m_nextPage++;
 
435
      }
 
436
 
 
437
      cLen = ( cRem > m_pageSize ) ? m_pageSize : cRem;
 
438
      memcpy( m_buffer, ptr, cLen );
 
439
 
 
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." );
 
444
 
 
445
      ptr += cLen;
 
446
      cRem -= cLen;
 
447
      e->m_pages.push_back( cPage );
 
448
    }
 
449
 
 
450
    while ( cNext < oldEntry->m_pages.size() )
 
451
    {
 
452
      m_emptyPages.push( oldEntry->m_pages[cNext] );
 
453
      cNext++;
 
454
    }
 
455
 
 
456
    m_pageIndex.insert( std::pair<long, Entry*>( id, e ) );
 
457
    delete oldEntry;
 
458
  }
 
459
}
 
460
 
 
461
void DiskStorageManager::deleteByteArray( const long id )
 
462
{
 
463
  map<long, Entry*>::iterator it = m_pageIndex.find( id );
 
464
 
 
465
  if ( it == m_pageIndex.end() ) throw Tools::InvalidPageException( id );
 
466
 
 
467
  for ( unsigned long cIndex = 0; cIndex < ( *it ).second->m_pages.size(); cIndex++ )
 
468
  {
 
469
    m_emptyPages.push(( *it ).second->m_pages[cIndex] );
 
470
  }
 
471
 
 
472
  delete( *it ).second;
 
473
  m_pageIndex.erase( it );
 
474
}
 
475