summaryrefslogtreecommitdiff
path: root/TAO/orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.h
blob: 97ea0556f366b2015948c3fbed71c9caaf29b572 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/* -*- C++ -*- */

//=============================================================================
/**
 *  @file    Persistent_File_Allocator.h
 *
 *  $Id$
 *
 *  A Persistent_File_Allocator manages a free list and allocates and
 *  deallocates blocks from a Random_File.  There should be only one
 *  Persistent_File_Allocator for each Random_File.
 *
 *  @author Jonathan Pollack <pollack_j@ociweb.com>
 */
//=============================================================================

#ifndef PERSISTENT_FILE_ALLOCATOR_H
#define PERSISTENT_FILE_ALLOCATOR_H
#include /**/ "ace/pre.h"
#include /**/ "ace/config-all.h"

#if !defined (ACE_LACKS_PRAGMA_ONCE)
#pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */

#include "notify_serv_export.h"
#include "Random_File.h"
#include "Bit_Vector.h"
#include "ace/Containers_T.h"
#include "ace/Unbounded_Queue.h"
#include "ace/Thread_Manager.h"

namespace TAO_Notify
{


/// \brief An interface to allow callbacks on completion of persistent storage
/// requests.
class TAO_Notify_Serv_Export Persistent_Callback
{
public:
  /// \brief Called by a Persistent_File_Allocator when a write request has
  /// completed.
  virtual void persist_complete() = 0;
};

/**
 * \brief A class to represent a block on disk.
 *
 * Contains the raw data to be written on disk as well as
 * positioning information, synchronization information, and a pointer
 * to a callback.
 */
class TAO_Notify_Serv_Export Persistent_Storage_Block
{
public:
  /// The constructor.  Initializes the callback to NULL.
  Persistent_Storage_Block(
    const size_t block_number,
    const size_t block_size);
  /// The copy constructor.  Makes a deep copy of the passed in PSB.
  Persistent_Storage_Block(const Persistent_Storage_Block& psb);
  /// The destructor.
  ~Persistent_Storage_Block();

  /// Set our block to not have any data at all - a no-op.  This can be
  /// used to implement a checkpoint in the write stream.
  void set_no_write();
  /// Find out whether we have data to be written.
  bool get_no_write();

  /// Set our block to be written as a near-atomic operation.
  void set_sync();
  /// Find out whether this block should be written near-atomically.
  bool get_sync() const;

  /// Find out our physical block number.
  size_t block_number() const;

  /// Return our data to the user.
  unsigned char* data() const;
  /// Set our data pointer, and optionally delete it.
  void reassign_data(unsigned char* newptr, bool delete_old = false);

  /// Return block number and relinquish ownership.
  size_t detach ();

  /// Set our callback.
  void set_callback(Persistent_Callback* callback);
  /// Get our callback.
  Persistent_Callback* get_callback() const;

  /// Set ownership of this PSB.
  void set_allocator_owns(bool allocator_owns = true);
  /// Get ownership status of this PSB.
  bool get_allocator_owns() const;

private:
  /// Our raw data.
  unsigned char* data_;
  /// The block number corresponding to our data.
  size_t block_number_;
  /// Are we a no-op with just a callback?
  bool no_write_;
  /// Write in near-atomic fashion.
  bool sync_;
  /// The size of our block.
  size_t block_size_;
  /// Our optional callback function, to be used in such things as state
  /// transitions.
  Persistent_Callback* callback_;
  /// Does the allocator obtain ownership of our block?
  bool allocator_owns_;
};

/**
 * \brief A class that manages the details of persistent storage.
 *
 * Maintains a free list, write queue, allocations of new
 * blocks, reads, and writes.  This class also manages a thread that performs
 * background updating of a Random_File.
 * @@todo this is too much for one class to do.  It should be refactored.
 * @@todo: we shouldn't arbitrarily use a thread.
 */
class TAO_Notify_Serv_Export Persistent_File_Allocator
{
public:
  /// The constructor.
  Persistent_File_Allocator();
  /// The destructor.
  ~Persistent_File_Allocator();

  bool open (const char* filename,
    const size_t block_size = 512);

  /// \brief Wait for pending I/O and terminate our work thread.
  void shutdown();

  /// Allocate a new Persistent_Storage_Block and initialize it to an unused
  /// block of storage.
  Persistent_Storage_Block* allocate();

  /// \brief Allocate a new Persistent_Storage_Block at a given address
  Persistent_Storage_Block* allocate_at(size_t block_number);

  /// \brief Allocate a PSB that is marked to not persist
  Persistent_Storage_Block* allocate_nowrite();

  /// \brief Mark a block as used, removing it from the free list.
  void used(size_t block_number);

  /// \brief Mark a block number as able to be used again.
  void free(size_t block_number);

  /// \brief Access block size.
  size_t block_size() const;

  /// \brief Read data into a PSB.
  ///
  /// Data will come either from the queue of blocks to be written, or
  /// it will be read from the file if there are no queued write requests for
  /// this block.
  bool read(Persistent_Storage_Block* psb);

  /// \brief Write this block to the file,
  ///
  /// Add the Persistent_Storage_Block to our write queue and let the
  /// worker thread handle writing this to the Random_File.
  bool write(Persistent_Storage_Block* psb);

  /// for information (unit test) only.
  size_t file_size () const;

private:
  /// Free a previously assigned block.
  void free_block(const size_t block_number);
  /// Find and allocate a free block.
  bool allocate_block(size_t& block_number);

  /// Used during thread startup to cast us back to ourselves and call the
  /// run() method.
  static ACE_THR_FUNC_RETURN thr_func(void * arg);
  /// Wait for pending I/O to complete and shut our worker thread down safely.
  void shutdown_thread();
  /// The worker's execution thread.
  void run();

private:
  ACE_Thread_Manager thread_manager_;
  Random_File pstore_;
  Bit_Vector free_blocks_;
  ACE_Unbounded_Queue<Persistent_Storage_Block*> block_queue_;
  ACE_SYNCH_MUTEX lock_;
  ACE_SYNCH_MUTEX free_blocks_lock_;
  ACE_SYNCH_MUTEX queue_lock_;
  bool terminate_thread_;
  bool thread_active_;
  ACE_SYNCH_CONDITION wake_up_thread_;
};

} /* namespace TAO_Notify */

#include /**/ "ace/post.h"
#endif /* PERSISTENT_FILE_ALLOCATOR_H */