NCBI C++ ToolKit
memory_store.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: memory_store.cpp 72088 2016-04-14 19:07:55Z ucko $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Vladimir Soussov
27  *
28  * File Description: RAM storage implementation
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 #include <dbapi/error_codes.hpp>
34 #include "memory_store.hpp"
35 #include <string.h>
36 
37 
38 #define NCBI_USE_ERRCODE_X Dbapi_DrvrMemStore
39 
40 
42 
43 
45 {
46  SMemBlock* n_blk = new SMemBlock;
47 
48  if ( !n_blk )
49  return 0;
50 
51  n_blk->body = new char[m_BlockSize];
52  if ( !n_blk->body ) {
53  delete n_blk;
54  return 0;
55  }
56 
57  n_blk->next = 0;
58  n_blk->free_space = m_BlockSize;
59  n_blk->prev = m_Last;
60 
61  if (m_First) {
62  m_Last->next = n_blk;
63  } else {
64  m_First = m_Current = n_blk;
65  }
66 
67  m_Last = n_blk;
68 
69  return n_blk;
70 }
71 
72 
73 size_t CMemStore::Append(const void* buff, size_t size)
74 {
75  if (!buff || !size)
76  return 0;
77 
78  if (!m_Last || !m_Last->free_space) {
79  if ( !x_AddBlock() )
80  return 0;
81  }
82 
83  TSize f_free;
84  TSize n = 0;
85  char* b = (char*) buff;
87  TSize nof_bytes = (TSize) size;
88 
89  while (nof_bytes > 0) {
90  f_free = m_BlockSize - m_Last->free_space;
91 
92  if (nof_bytes <= m_Last->free_space) {
93  // we have enough space in last block
94  memcpy(&m_Last->body[f_free], b+n, nof_bytes);
95  m_Last->free_space -= nof_bytes;
96  n += nof_bytes;
97  break;
98  }
99  // space in this block is insufficient
100 
101  memcpy(&m_Last->body[f_free], b + n, m_Last->free_space);
102  n += m_Last->free_space;
103  nof_bytes -= m_Last->free_space;
104  m_Last->free_space = 0;
105  if ( !x_AddBlock() )
106  break;
107  }
108  m_Size += n;
109  return (size_t) n;
110 }
111 
112 
113 size_t CMemStore::Read(void* buff, size_t size)
114 {
115 
116  if (!m_Current || !buff || !size)
117  return 0;
118 
120 
121  TSize n = 0;
122  char* b = (char*) buff;
123 
124  for (TSize nof_bytes = (TSize) size; nof_bytes > 0; ) {
126 
127  if ((m_BlockPos + nof_bytes) <= f_free) {
128  // we have all needed bytes in this block
129  memcpy(b, &m_Current->body[m_BlockPos], nof_bytes);
130  m_BlockPos += nof_bytes;
131  n += nof_bytes;
132  if (m_BlockPos >= f_free) {
133  // we have read all bytes from this block
135  m_BlockPos = 0;
136  }
137  break;
138  }
139  // we can read just a part from this block
140  TSize k = f_free - m_BlockPos;
141  memcpy(b, &m_Current->body[m_BlockPos], k);
142  n += k;
143  b += k;
144  nof_bytes -= k;
145  m_BlockPos = 0;
146 
148  if ( !m_Current )
149  break;
150  }
151 
152  m_Pos += n;
153  return (size_t) n;
154 }
155 
156 
157 size_t CMemStore::Peek(void* buff, size_t size) const
158 {
159  // Work with a partial shallow copy to avoid code duplication.
160  // (No need for m_First, m_Last, or m_Size.)
161  CMemStore ms2(m_BlockSize);
162  ms2.m_Current = m_Current;
163  ms2.m_Pos = m_Pos;
164  ms2.m_BlockPos = m_BlockPos;
165  return ms2.Read(buff, size);
166 }
167 
168 
169 size_t CMemStore::PeekAt(void* buff, size_t start, size_t size) const
170 {
171  // Work with a shallow copy to avoid code duplication.
172  CMemStore ms2(m_BlockSize);
173  ms2.m_First = m_First;
174  ms2.m_Current = m_Current;
175  ms2.m_Pos = m_Pos;
176  ms2.m_BlockPos = m_BlockPos;
177  ms2.m_Size = m_Size;
178  // Set m_Last for the sake of Seek, but make sure it winds up NULL
179  // to avoid premature cleanup.
180  try {
181  ms2.m_Last = m_Last;
182  ms2.Seek(start, eHead);
183  } catch (...) {
184  ms2.m_Last = NULL;
185  throw;
186  }
187  ms2.m_Last = NULL;
188  return ms2.Read(buff, size);
189 }
190 
191 
193 {
194  if ( !m_Current )
195  return x_SeekTAIL(offset);
196 
197  if (offset == 0)
198  return m_Pos;
199 
200  if (offset <= -m_Pos)
201  return x_SeekHEAD(0);
202 
203  if (offset > 0) {
204  // go toward the tail
205  while (offset > 0) {
207 
208  if ((m_BlockPos + offset) < n) {
209  // we have to move inside this block
210  m_BlockPos += offset;
211  m_Pos += offset;
212  break;
213  }
214  // we have to move outside the block
215  n -= m_BlockPos;
216  m_Pos += n;
217  m_BlockPos = 0;
219  if (!m_Current)
220  break;
221  offset -= n;
222  }
223  }
224  else {
225  // go toward the head
226  while (offset < 0) {
227  if ((m_BlockPos + offset) >= 0) {
228  // we have to move inside this block
229  m_BlockPos += offset;
230  m_Pos += offset;
231  break;
232  }
233  // we have to move outside the block
234  m_Pos -= m_BlockPos + 1;
235  offset += m_BlockPos + 1;
238  }
239  }
240 
241  return m_Pos;
242 }
243 
244 
246 {
247  if (offset <= 0) {
248  m_Current = m_First;
249  m_Pos = 0;
250  m_BlockPos = 0;
251  return 0;
252  }
253 
254  if (offset == m_Pos)
255  return m_Pos;
256 
257  if (!m_Current || (offset < m_Pos && offset < m_Pos - offset)) {
258  x_SeekHEAD(0);
259  return x_SeekCURR(offset);
260  }
261 
262  return x_SeekCURR(offset - m_Pos);
263 }
264 
265 
267 {
268  if (offset >= 0) {
269  m_BlockPos = 0;
270  m_Current = 0;
271  m_Pos = m_Size;
272  return m_Pos;
273  }
274 
275  return x_SeekHEAD(m_Size + offset);
276 }
277 
278 
279 long CMemStore::Seek(long offset, EWhence whence)
280 {
281  if ( !m_Last )
282  return -1;
283 
284  switch (whence) {
285  case eHead:
286  return (long) x_SeekHEAD((TSize) offset);
287  case eTail:
288  return (long) x_SeekTAIL((TSize) offset);
289  case eCurr:
290  return (long) x_SeekCURR((TSize) offset);
291  }
292 
293  return -1; // error
294 }
295 
296 
297 size_t CMemStore::Write(const void* buff, size_t size)
298 {
299  if (!buff || !size)
300  return 0;
301 
303 
304  char* b = (char*) buff;
305  TSize nof_bytes = (TSize) size;
306 
307  TSize n = 0;
308 
309  if ( m_Current ) {
310  while (nof_bytes > 0) {
312 
313  if ((m_BlockPos + nof_bytes) <= f_free) {
314  // we have all needed bytes in this block
315  memcpy(&m_Current->body[m_BlockPos], b + n, nof_bytes);
316  m_BlockPos += nof_bytes;
317  n += nof_bytes;
318  nof_bytes = 0;
319  if (m_BlockPos >= f_free) {
320  // we have written all bytes to this block
322  m_BlockPos = 0;
323  }
324  break;
325  }
326 
327  // we can write just a part to this block
328  TSize k = f_free - m_BlockPos;
329  memcpy(&m_Current->body[m_BlockPos], b + n, k);
330  n += k;
331  nof_bytes -= k;
332  m_BlockPos = 0;
333 
335  if ( !m_Current )
336  break;
337  }
338  }
339 
340  if (nof_bytes > 0) {
341  n += static_cast<TSize>(Append(b + n, nof_bytes));
342  x_SeekTAIL(0);
343  }
344  else {
345  m_Pos += n;
346  }
347 
348  return n;
349 }
350 
351 
352 size_t CMemStore::Truncate(size_t size)
353 {
355 
356  TSize nof_bytes = (TSize) size;
357 
358  if (nof_bytes >= m_Size) {
359  for ( ; m_Last != NULL; m_Last = m_Current) {
360  m_Current = m_Last->prev;
361  delete [] m_Last->body;
362  delete m_Last;
363  }
364  m_First = m_Last = m_Current = 0;
365  m_BlockPos = m_Pos = m_Size = 0;
366  return 0;
367  }
368 
369  while (nof_bytes > 0) {
371  if (n <= nof_bytes) {
372  // we have to delete the whole block
373  delete [] m_Last->body;
374  SMemBlock* t = m_Last->prev;
375  _ASSERT(t != NULL);
376  t->next = NULL;
377  delete m_Last;
378  _ASSERT(m_Last != t);
379  m_Last = t;
380  nof_bytes -= n;
381  m_Size -= n;
382  continue;
383  }
384  // we have to free some bytes
385  m_Last->free_space += nof_bytes;
386  m_Size -= nof_bytes;
387  break;
388  }
389 
390  if (m_Pos >= m_Size) {
391  m_Pos = m_Size;
392  m_Current = 0;
393  m_BlockPos = 0;
394  }
395 
396  return m_Size;
397 }
398 
399 
400 size_t CMemStore::Insert(const void* buff, size_t size)
401 {
402  if (!buff || !size)
403  return 0;
404 
406 
407  if ( !m_Current )
408  return Append(buff, size);
409 
410  char* b = (char*) buff;
411  TSize nof_bytes = (TSize) size;
412  TSize n = 0;
413 
414  while (nof_bytes > 0) {
415  // first empty byte in this block
417  // number of bytes to move
418  TSize k = f_free - m_BlockPos;
419 
420  if (nof_bytes <= m_Current->free_space) {
421  // we can add this to existing block
422  memmove(&m_Current->body[m_BlockPos + nof_bytes],
423  &m_Current->body[m_BlockPos], k);
424  memcpy(&m_Current->body[m_BlockPos], b + n, nof_bytes);
425  m_Current->free_space -= nof_bytes;
426  n += nof_bytes;
427  m_BlockPos += nof_bytes;
428  nof_bytes = 0;
429  break;
430  }
431 
432  // there is no enaugh space in existing block -- split it
433  SMemBlock* t_block = new SMemBlock;
434 
435  t_block->body = new char[m_BlockSize];
436 
437  t_block->next = m_Current->next;
438  if (t_block->next)
439  t_block->next->prev = t_block;
440  m_Current->next = t_block;
441  t_block->prev = m_Current;
442 
443  memcpy(t_block->body, &m_Current->body[m_BlockPos], k);
444  t_block->free_space = m_BlockSize - k;
445  m_Current->free_space += k;
446 
447  k = (nof_bytes <= m_Current->free_space)
448  ? nof_bytes : m_Current->free_space;
449  memcpy(&m_Current->body[m_BlockPos], b + n, k);
450  m_Current->free_space -= k;
451  nof_bytes -= k;
452  n += k;
453  if (m_Last == m_Current)
454  m_Last = t_block;
455  m_Current = t_block;
456  m_BlockPos = 0;
457  }
458  m_Pos += n;
459  m_Size += n;
460 
461  // try to merge the two last blocks
462  SMemBlock* t_block = m_Current->next;
463  if (t_block != NULL
464  && (m_Current->free_space + t_block->free_space) >= m_BlockSize) {
466  TSize k = m_BlockSize - t_block->free_space;
467  memcpy(&m_Current->body[f_free], t_block->body, k);
468  m_Current->free_space -= k;
469  _ASSERT(m_Current->next != t_block->next);
470  m_Current->next = t_block->next;
471  if (m_Current->next) {
473  } else {
474  m_Last = m_Current;
475  }
476  delete [] t_block->body;
477  delete t_block;
478  }
479  return n;
480 }
481 
482 
483 size_t CMemStore::Delete(size_t size)
484 {
485  if (!m_Last || !size)
486  return m_Size;
487 
489 
490  if ( !m_Current )
491  return Truncate(size);
492 
493  TSize nof_bytes = (TSize) size;
494 
495  if (m_BlockPos >= nof_bytes) {
496  // just one block is affected
497  memmove(&m_Current->body[m_BlockPos - nof_bytes],
500  m_Current->free_space += nof_bytes;
501  m_BlockPos -= nof_bytes;
502  m_Pos -= nof_bytes;
503  m_Size -= nof_bytes;
504  return m_Size;
505  }
506 
507  // we can affect several blocks...
508  if (m_BlockPos > 0) {
512  nof_bytes -= m_BlockPos;
513  m_Pos -= m_BlockPos;
514  m_Size -= m_BlockPos;
515  m_BlockPos = 0;
516  }
517 
518  while (nof_bytes > 0) {
519  SMemBlock* t_block = m_Current->prev;
520  if ( !t_block ) {
521  m_First = m_Current;
522  break;
523  }
524 
525  TSize n = m_BlockSize - t_block->free_space; // # of bytes in this block
526  if (nof_bytes < n) {
527  // all we have to delete is inside the block
528  t_block->free_space += nof_bytes;
529  m_Pos -= nof_bytes;
530  m_Size -= nof_bytes;
531  break;
532  }
533  // delete the whole block
534  if (t_block->prev)
535  t_block->prev->next = m_Current;
536  else
537  m_First = m_Current;
538 
539  _ASSERT(m_Current->prev != t_block->prev);
540  m_Current->prev = t_block->prev;
541  delete [] t_block->body;
542  delete t_block;
543  m_Pos -= n;
544  m_Size -= n;
545  nof_bytes -= n;
546  }
547 
548  return m_Size;
549 }
550 
551 
552 CMemStore::CMemStore(C_SA_Storage& storage, size_t block_size)
553 {
554  if(block_size > kMax_BlobSize) block_size= kMax_BlobSize;
555  x_Init((TSize) block_size);
556 
557  char* buff = new char[m_BlockSize];
558  TSize n;
559 
560  while ((n = static_cast<TSize>(storage.Read(buff,
561  (size_t) m_BlockSize))) > 0) {
562  Append(buff, n);
563  if (n < m_BlockSize)
564  break;
565  }
566 }
567 
568 
570 {
571  try {
572  while ( m_Last ) {
573  m_Current = m_Last->prev;
574  delete [] m_Last->body;
575  delete m_Last;
577  m_Last = m_Current;
578  }
579  }
581 }
582 
583 
585 
586 
TSize m_BlockPos
size_t Read(void *buff, size_t nof_bytes)
size_t Peek(void *buff, size_t nof_bytes) const
void x_Init(TSize block_size=2048)
size_t Delete(size_t nof_bytes=kMax_BlobSize)
size_t Write(const void *buff, size_t nof_bytes)
TSize x_SeekTAIL(TSize offset)
TSize m_BlockSize
TSize x_SeekHEAD(TSize offset)
SMemBlock * m_Current
size_t Truncate(size_t nof_bytes=kMax_BlobSize)
long Seek(long offset, EWhence whence)
size_t PeekAt(void *buff, size_t start, size_t n) const
size_t Append(const void *buff, size_t nof_bytes)
SMemBlock * x_AddBlock(void)
size_t Insert(const void *buff, size_t nof_bytes)
SMemBlock * m_First
SMemBlock * m_Last
TSize x_SeekCURR(TSize offset)
virtual size_t Read(void *buff, size_t nof_bytes)=0
#define NULL
Definition: ncbistd.hpp:225
#define NCBI_CURRENT_FUNCTION
Get current function name.
Definition: ncbidiag.hpp:142
#define NCBI_CATCH_ALL_X(err_subcode, message)
Definition: ncbiexpt.hpp:619
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
Definition of all error codes used in dbapi libraries (dbapi_driver.lib and others).
yy_size_t n
static size_t kMax_BlobSize
const struct ncbi::grid::netcache::search::fields::SIZE size
EIPRangeType t
Definition: ncbi_localip.c:101
#define memmove(a, b, c)
int offset
Definition: replacements.h:160
#define _ASSERT
Modified on Thu Dec 07 10:08:10 2023 by modify_doxy.py rev. 669887