00001 // -*- C++ -*- 00002 00003 //============================================================================= 00004 /** 00005 * @file Persistent_File_Allocator.h 00006 * 00007 * $Id: Persistent_File_Allocator.h 81420 2008-04-24 12:13:54Z johnnyw $ 00008 * 00009 * A Persistent_File_Allocator manages a free list and allocates and 00010 * deallocates blocks from a Random_File. There should be only one 00011 * Persistent_File_Allocator for each Random_File. 00012 * 00013 * @author Jonathan Pollack <pollack_j@ociweb.com> 00014 */ 00015 //============================================================================= 00016 00017 #ifndef PERSISTENT_FILE_ALLOCATOR_H 00018 #define PERSISTENT_FILE_ALLOCATOR_H 00019 #include /**/ "ace/pre.h" 00020 #include /**/ "ace/config-all.h" 00021 00022 #if !defined (ACE_LACKS_PRAGMA_ONCE) 00023 #pragma once 00024 #endif /* ACE_LACKS_PRAGMA_ONCE */ 00025 00026 #include "orbsvcs/Notify/notify_serv_export.h" 00027 #include "orbsvcs/Notify/Random_File.h" 00028 #include "orbsvcs/Notify/Bit_Vector.h" 00029 #include "ace/Containers_T.h" 00030 #include "ace/Unbounded_Queue.h" 00031 #include "ace/Thread_Manager.h" 00032 00033 TAO_BEGIN_VERSIONED_NAMESPACE_DECL 00034 00035 namespace TAO_Notify 00036 { 00037 00038 /// \brief An interface to allow callbacks on completion of persistent storage 00039 /// requests. 00040 class TAO_Notify_Serv_Export Persistent_Callback 00041 { 00042 public: 00043 virtual ~Persistent_Callback(); 00044 /// \brief Called by a Persistent_File_Allocator when a write request has 00045 /// completed. 00046 virtual void persist_complete() = 0; 00047 }; 00048 00049 /** 00050 * \brief A class to represent a block on disk. 00051 * 00052 * Contains the raw data to be written on disk as well as 00053 * positioning information, synchronization information, and a pointer 00054 * to a callback. 00055 */ 00056 class TAO_Notify_Serv_Export Persistent_Storage_Block 00057 { 00058 public: 00059 /// The constructor. Initializes the callback to NULL. 00060 Persistent_Storage_Block( 00061 const size_t block_number, 00062 const size_t block_size); 00063 /// The copy constructor. Makes a deep copy of the passed in PSB. 00064 Persistent_Storage_Block(const Persistent_Storage_Block& psb); 00065 /// The destructor. 00066 ~Persistent_Storage_Block(); 00067 00068 /// Set our block to not have any data at all - a no-op. This can be 00069 /// used to implement a checkpoint in the write stream. 00070 void set_no_write(); 00071 /// Find out whether we have data to be written. 00072 bool get_no_write(); 00073 00074 /// Set our block to be written as a near-atomic operation. 00075 void set_sync(); 00076 /// Find out whether this block should be written near-atomically. 00077 bool get_sync() const; 00078 00079 /// Find out our physical block number. 00080 size_t block_number() const; 00081 00082 /// Return our data to the user. 00083 unsigned char* data() const; 00084 /// Set our data pointer, and optionally delete it. 00085 void reassign_data(unsigned char* newptr, bool delete_old = false); 00086 00087 /// Return block number and relinquish ownership. 00088 size_t detach (); 00089 00090 /// Set our callback. 00091 void set_callback(Persistent_Callback* callback); 00092 /// Get our callback. 00093 Persistent_Callback* get_callback() const; 00094 00095 /// Set ownership of this PSB. 00096 void set_allocator_owns(bool allocator_owns = true); 00097 /// Get ownership status of this PSB. 00098 bool get_allocator_owns() const; 00099 00100 private: 00101 /// Our raw data. 00102 unsigned char* data_; 00103 /// The block number corresponding to our data. 00104 size_t block_number_; 00105 /// Are we a no-op with just a callback? 00106 bool no_write_; 00107 /// Write in near-atomic fashion. 00108 bool sync_; 00109 /// The size of our block. 00110 size_t block_size_; 00111 /// Our optional callback function, to be used in such things as state 00112 /// transitions. 00113 Persistent_Callback* callback_; 00114 /// Does the allocator obtain ownership of our block? 00115 bool allocator_owns_; 00116 }; 00117 00118 /** 00119 * \brief A class that manages the details of persistent storage. 00120 * 00121 * Maintains a free list, write queue, allocations of new 00122 * blocks, reads, and writes. This class also manages a thread that performs 00123 * background updating of a Random_File. 00124 * @todo this is too much for one class to do. It should be refactored. 00125 * @todo we shouldn't arbitrarily use a thread. 00126 */ 00127 class TAO_Notify_Serv_Export Persistent_File_Allocator 00128 { 00129 public: 00130 /// The constructor. 00131 Persistent_File_Allocator(); 00132 /// The destructor. 00133 ~Persistent_File_Allocator(); 00134 00135 bool open (const ACE_TCHAR* filename, 00136 const size_t block_size = 512); 00137 00138 /// \brief Wait for pending I/O and terminate our work thread. 00139 void shutdown(); 00140 00141 /// Allocate a new Persistent_Storage_Block and initialize it to an unused 00142 /// block of storage. 00143 Persistent_Storage_Block* allocate(); 00144 00145 /// \brief Allocate a new Persistent_Storage_Block at a given address 00146 Persistent_Storage_Block* allocate_at(size_t block_number); 00147 00148 /// \brief Allocate a PSB that is marked to not persist 00149 Persistent_Storage_Block* allocate_nowrite(); 00150 00151 /// \brief Mark a block as used, removing it from the free list. 00152 void used(size_t block_number); 00153 00154 /// \brief Mark a block number as able to be used again. 00155 void free(size_t block_number); 00156 00157 /// \brief Access block size. 00158 size_t block_size() const; 00159 00160 /// \brief Read data into a PSB. 00161 /// 00162 /// Data will come either from the queue of blocks to be written, or 00163 /// it will be read from the file if there are no queued write requests for 00164 /// this block. 00165 bool read(Persistent_Storage_Block* psb); 00166 00167 /// \brief Write this block to the file, 00168 /// 00169 /// Add the Persistent_Storage_Block to our write queue and let the 00170 /// worker thread handle writing this to the Random_File. 00171 bool write(Persistent_Storage_Block* psb); 00172 00173 /// for information (unit test) only. 00174 ACE_OFF_T file_size () const; 00175 00176 private: 00177 /// Free a previously assigned block. 00178 void free_block(const size_t block_number); 00179 /// Find and allocate a free block. 00180 bool allocate_block(size_t& block_number); 00181 00182 /// Used during thread startup to cast us back to ourselves and call the 00183 /// run() method. 00184 static ACE_THR_FUNC_RETURN thr_func(void * arg); 00185 /// Wait for pending I/O to complete and shut our worker thread down safely. 00186 void shutdown_thread(); 00187 /// The worker's execution thread. 00188 void run(); 00189 00190 private: 00191 ACE_Thread_Manager thread_manager_; 00192 Random_File pstore_; 00193 Bit_Vector free_blocks_; 00194 ACE_Unbounded_Queue<Persistent_Storage_Block*> block_queue_; 00195 TAO_SYNCH_MUTEX lock_; 00196 TAO_SYNCH_MUTEX free_blocks_lock_; 00197 TAO_SYNCH_MUTEX queue_lock_; 00198 bool terminate_thread_; 00199 bool thread_active_; 00200 ACE_SYNCH_CONDITION wake_up_thread_; 00201 }; 00202 00203 } /* namespace TAO_Notify */ 00204 00205 TAO_END_VERSIONED_NAMESPACE_DECL 00206 00207 #include /**/ "ace/post.h" 00208 #endif /* PERSISTENT_FILE_ALLOCATOR_H */