Source for file class.Channel_Buffer_Mem.inc

Documentation is available at class.Channel_Buffer_Mem.inc

  1. <?php //-*-php-*-
  2. /* ******************************************************************** **
  3. ** Copyright notice **
  4. ** **
  5. ** (c) 1995-2003 PHPOpenChat Development Team **
  6. ** http://phpopenchat.sourceforge.net/ **
  7. ** **
  8. ** All rights reserved **
  9. ** **
  10. ** This script is part of the PHPOpenChat project. The PHPOpenChat **
  11. ** project is free software; you can redistribute it and/or modify **
  12. ** it under the terms of the GNU General Public License as published by **
  13. ** the Free Software Foundation; either version 2 of the License, or **
  14. ** (at your option) any later version. **
  15. ** **
  16. ** The GNU General Public License can be found at **
  17. ** http://www.gnu.org/copyleft/gpl.html. **
  18. ** A copy is found in the textfile GPL and important notices to the **
  19. ** license from the team is found in the textfile LICENSE distributed **
  20. ** with these scripts. **
  21. ** **
  22. ** This script is distributed in the hope that it will be useful, **
  23. ** but WITHOUT ANY WARRANTY; without even the implied warranty of **
  24. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the **
  25. ** GNU General Public License for more details. **
  26. ** **
  27. ** This copyright notice MUST APPEAR in all copies of the script! **
  28. ** ******************************************************************** */
  29.  
  30. // Class Channel_Buffer based on Shared Memory (Unix only)
  31. //Get default values
  32.  
  33. require_once(POC_BASE.'/config.inc.php');
  34. require_once(POC_INCLUDE_PATH.'/class.Logger.inc');
  35.  
  36. // shared memory stores variables only under integer keys
  37. // therefore we need some constants
  38.  
  39.  
  40.  
  41. define("CB_INIT_FLAG",0); // channel buffer init flag
  42. define("CB_MAX_LINE_IDX",1); // channel buffer maximum line number shm index
  43. define("CB_CUR_LINE_IDX",2); // channel buffer current line number shm index
  44. define("CB_LINE_OFFSET",3); // channel buffer line array index offset
  45. // CB_LINE_MEMORY = strlen(serialize($maximum_length_line_object))
  46.  
  47. define("CB_LINE_MEMORY",2048); // channel buffer shared memory per line in bytes
  48.  
  49. /**
  50. * Channel buffer based on shared memory
  51. *
  52. * @package phpopenchat
  53. * @author Frerk Meyer <frerk@sourceforge.net>
  54. * @access public
  55. * @version $Id: class.Channel_Buffer_Mem.inc,v 1.24 2003/08/06 12:19:36 letreo Exp $
  56. * @todo move remove_lock() to disconnect()
  57. * @todo get_cur_idx() should read shared memory?
  58. */
  59.  
  60. class Channel_Buffer {
  61.  
  62. /**
  63. * channel name
  64. *
  65. * @var string
  66. * @access public
  67. * @see Channel_Buffer()
  68. */
  69. var $channel;
  70. /**
  71. * channel id 32-bit based on channel name
  72. * needed for shared memory and semaphores
  73. *
  74. * @var string
  75. * @access private
  76. * @see Channel_Buffer()
  77. */
  78. var $channel_id;
  79.  
  80. /**
  81. * Semaphore Id for channel buffer locking
  82. *
  83. * @var int
  84. * @access private
  85. * @see Channel_Buffer()
  86. * @see lock()
  87. * @see unlock()
  88. */
  89. var $sem_id;
  90.  
  91. /**
  92. * Shared memory Id for channel buffer storage
  93. *
  94. * @var int
  95. * @access private
  96. * @see Channel_Buffer()
  97. */
  98. var $shm_id;
  99.  
  100. /**
  101. * Maximum line index of channel buffer
  102. *
  103. * @var int
  104. * @access private
  105. * @see Channel_Buffer()
  106. */
  107. var $max_line_idx;
  108.  
  109. /**
  110. * Current line index of channel buffer
  111. *
  112. * @var int
  113. * @access private
  114. * @see Channel_Buffer()
  115. */
  116. var $cur_line_idx;
  117.  
  118. var $locked;
  119.  
  120. var $connected;
  121.  
  122. /**
  123. * Constructor
  124. *
  125. * create a new channel buffer object with name 'channel'
  126. *
  127. * @param string $channel
  128. * @access public
  129. */
  130. function Channel_Buffer ($channel) {
  131. $this->channel = $channel;
  132. $this->channel_id = crc32($channel);
  133. $this->max_line_idx = CB_MAX_LINE;
  134. $this->cur_line_idx = 0;
  135. $this->sem_id = 0;
  136. $this->shm_id = 0;
  137. $this->locked = 0;
  138. $this->connected = 0;
  139. }
  140.  
  141. /**
  142. * Get maximum line index
  143. *
  144. * @access public
  145. * @return int max_line_idx
  146. */
  147. function get_max_line_idx() {
  148. if (!$this->connected) $this->connect();
  149. $this->lock();
  150. $this->cur_line_idx = shm_get_var($this->shm_id,CB_CUR_LINE_IDX);
  151. return $this->max_line_idx;
  152. $this->unlock();
  153. }
  154.  
  155. /**
  156. * Get current line index
  157. *
  158. * @access public
  159. * @return int cur_line_idx
  160. */
  161. function get_cur_line_idx() {
  162. if (!$this->connected) $this->connect();
  163. $this->lock();
  164. $this->cur_line_idx = shm_get_var($this->shm_id,CB_CUR_LINE_IDX);
  165. return $this->cur_line_idx;
  166. $this->unlock();
  167. }
  168.  
  169. /**
  170. * Get channel name
  171. *
  172. * @access public
  173. * @return string channel
  174. */
  175. function get_name() {
  176. return $this->channel;
  177. }
  178.  
  179. /**
  180. * Lock access to shared memory with a semaphore
  181. *
  182. * Semaphore is created by connect()
  183. *
  184. * @access private
  185. * @return int semaphore id
  186. * @see connect()
  187. */
  188. function lock() {
  189. if (!$this->locked) { // lock only if unlocked
  190. // lock for only one process and read/write for owner only
  191. if (!sem_acquire($this->sem_id)) die ("can't aquire channel buffer semaphore");
  192. $this->locked = true;
  193. }
  194. return true;
  195. }
  196.  
  197. /**
  198. * Unlock access to shared memory with a semaphore
  199. *
  200. * To remove sempahore use remove_lock()
  201. *
  202. * @access private
  203. * @return int semaphore id
  204. * @see remove_lock()
  205. */
  206. function unlock() {
  207. if ($this->locked) { // unlock only if locked
  208. if (!sem_release($this->sem_id)) die ("can't release channel buffer semaphore");
  209. $this->locked = false; // status unlocked
  210. }
  211. return true;
  212. }
  213.  
  214. /**
  215. * Remove lock semaphore
  216. * TODO: Test if really needed and working, fm
  217. * @access private
  218. * @return int semaphore id
  219. */
  220. function remove_lock() {
  221. if (!$this->sem_id) {
  222. if (!sem_remove($this->sem_id)) die ("can't remove semaphore");
  223. $this->sem_id = 0;
  224. }
  225. return true;
  226. }
  227.  
  228. /**
  229. * Connect to the shared memory segment
  230. *
  231. * Create semaphore and shared memory segment if non-existant
  232. * Init if created
  233. *
  234. * @param string
  235. * @access public
  236. */
  237. function connect() { // connect and init
  238. // get semaphore id, create one if none exists
  239. if (!($this->sem_id = sem_get($this->channel_id,1,0600))) die ("can't get semaphore id");
  240. // get shared mem id, create one if none exists
  241. if (!($this->shm_id = shm_attach($this->channel_id,CB_LINE_MEMORY*$this->max_line_idx,0600)))
  242. die ("can't attach to channel buffer shared memory");
  243. if (!$this->connected)
  244. { // shm already attached?
  245. $this->connected=true;
  246. $this->lock();
  247. if (!@shm_remove_var($this->shm_id,CB_INIT_FLAG))
  248. { // init if created
  249. shm_put_var($this->shm_id,CB_INIT_FLAG,1);
  250. shm_put_var($this->shm_id,CB_MAX_LINE_IDX,$this->max_line_idx);
  251. shm_put_var($this->shm_id,CB_CUR_LINE_IDX,$this->cur_line_idx);
  252. for ($i=0; $i<$this->max_line_idx; $i++)
  253. {
  254. if (!shm_put_var($this->shm_id,$i+CB_LINE_OFFSET,"$i"))
  255. die ("can't write line $i to channel memory");
  256. }
  257. // TODO else get values from channel!!!
  258. $this->max_line_idx = shm_get_var($this->shm_id,CB_MAX_LINE_IDX);
  259. $this->cur_line_idx = shm_get_var($this->shm_id,CB_CUR_LINE_IDX);
  260. }
  261. else
  262. shm_put_var($this->shm_id,CB_INIT_FLAG,1);
  263. $this->unlock();
  264. }
  265. return true;
  266. }
  267.  
  268. function disconnect() {
  269. if ($this->connected) {
  270. $this->lock();
  271. // detach from channel memory and preserve data for other processes
  272. if (!shm_detach($this->shm_id)) die ("can't detach from channel buffer shared memory");
  273. $this->connected=false;
  274. $this->unlock();
  275. }
  276. }
  277.  
  278.  
  279. // initialize the channel buffer shared memory
  280. // creating a new one if necessary and
  281. // overwriting an existing one
  282.  
  283.  
  284. function init() {
  285. return true; // TODO: delete init() calls in main
  286. // get shared mem id, create one if none exists
  287. if (!($this->shm_id = shm_attach($this->channel_id,CB_LINE_MEMORY*$this->max_line_idx,0600))) die ("can't attach to channel buffer shared memory");
  288. shm_put_var($this->shm_id,CB_INIT_FLAG,1);
  289. shm_put_var($this->shm_id,CB_MAX_LINE_IDX,$this->max_line_idx);
  290. shm_put_var($this->shm_id,CB_CUR_LINE_IDX,$this->cur_line_idx);
  291. for ($i=0; $i<$this->max_line_idx; $i++) {
  292. if (!shm_put_var($this->shm_id,$i+CB_LINE_OFFSET,"$i")) die ("can't write line $i to channel memory");
  293. }
  294. return true;
  295. }
  296.  
  297. function destroy() {
  298. $this->lock();
  299. // remove channel memory and destroy data
  300. if (!($this->shm_id = shm_attach($this->channel_id))) die ("can't attach to channel buffer shared memory");
  301. if (!shm_remove($this->shm_id)) die ("can't remove channel buffer shared memory");
  302. $this->unlock();
  303. }
  304.  
  305. /**
  306. * Get current chat line object
  307. *
  308. * @access public
  309. * @return object Line
  310. */
  311. function get_cur_line() {
  312. $this->lock();
  313. // get current line
  314. $this->cur_line_idx = shm_get_var($this->shm_id,CB_CUR_LINE_IDX);
  315. $cur_line = shm_get_var($this->shm_id,$this->cur_line_idx+CB_LINE_OFFSET);
  316. $this->unlock();
  317. return $cur_line;
  318. }
  319.  
  320. /**
  321. * Get all chat lines since given index
  322. *
  323. * Idea is get all lines that were written by others
  324. * since the last line you have written
  325. *
  326. * @param int $since_idx
  327. * @access public
  328. * @return array of instances of class Chat_Line
  329. */
  330. function get_lines_since($since_idx) {
  331.  
  332. $i = 0;
  333.  
  334. $this->lock();
  335. // get max and current line index
  336. $this->max_line_idx = shm_get_var($this->shm_id,CB_MAX_LINE_IDX);
  337. $this->cur_line_idx = shm_get_var($this->shm_id,CB_CUR_LINE_IDX);
  338. if (($since_idx < 0) || ($since_idx >= $this->max_line_idx))
  339. $_SESSION['logger']->error('Line index '.$line_idx.' out of bounds exception',__FILE__,__LINE__);
  340. // read all lines from since to current
  341. $i = $since_idx;
  342. $lines = array();
  343. while ($i <> $this->cur_line_idx) {
  344. $i = ++$i % $this->max_line_idx; // modulo calculation for wrap around
  345. $lines[] = shm_get_var($this->shm_id,$i+CB_LINE_OFFSET);
  346. }
  347. // if array $lines[] is empty, nothing was put into buffer since last time
  348. $this->unlock();
  349. return $lines;
  350. }
  351.  
  352. function put_line($line) {
  353. /*
  354. if( is_object($_SESSION['logger']) )
  355. {
  356. print_r($line);exit;
  357. $sender = $line->get_sender();
  358. //$recipient = $line->get_recipient()
  359. $_SESSION['logger']->line($sender->get_nick().': '.$line->get_said());
  360. }
  361. */
  362. $this->lock();
  363. // put line as current into channel buffer
  364. $this->cur_line_idx = shm_get_var($this->shm_id,CB_CUR_LINE_IDX);
  365. $this->max_line = shm_get_var($this->shm_id,CB_MAX_LINE_IDX);
  366. $this->cur_line_idx = ++$this->cur_line_idx % $this->max_line_idx;
  367. shm_put_var($this->shm_id,$this->cur_line_idx+CB_LINE_OFFSET,$line);
  368. shm_put_var($this->shm_id,CB_CUR_LINE_IDX,$this->cur_line_idx);
  369. $this->unlock();
  370. return $this->cur_line_idx; // return index of current line
  371. }
  372.  
  373. /**
  374. * test method for class Channel_Buffer
  375. *
  376. * call like: Channel_Buffer::test();
  377. * initialize 2 channel buffers, write some lines
  378. * read them, disconnect and reconnect,
  379. * and verify the lines again
  380. * test function must work identical in Mem and DB version
  381. **/
  382.  
  383. function test() {
  384. $nl="<br>\n";
  385. // create 2 new channel buffers
  386. $cb1 = new Channel_Buffer("schulhof");
  387. $cb2 = new Channel_Buffer("lehrerzimmer");
  388. // connect (and create if non existent)
  389. $cb1->connect();
  390. $cb2->connect();
  391. // fill with test lines in mixed order
  392. $cb1_idx = $cb1->put_line("1:1");
  393. $cb1->put_line("1:2");
  394. $cb2->put_line("2:1");
  395. $cb2_idx = $cb2->put_line("2:2");
  396. $cb1->put_line("1:3");
  397. $cb2->put_line("2:3");
  398. // get test lines and print them
  399. // first channel buffer
  400. // expect "1:2","1:3"
  401. $lines = $cb1->get_lines_since($cb1_idx);
  402. foreach ($lines as $l) {
  403. print $cb1->get_name().": $l $nl";
  404. }
  405. // second channel buffer
  406. // expect "2:3"
  407. $lines = $cb2->get_lines_since($cb2_idx);
  408. foreach ($lines as $l) {
  409. print $cb2->get_name().": $l $nl";
  410. }
  411. // disconnect from channel buffer, don't remove them
  412. $cb1->disconnect();
  413. $cb2->disconnect();
  414. unset($cb1);
  415. unset($cb1_idx);
  416. unset($cb2);
  417. unset($cb2_idx);
  418. // reconnect to channel buffers
  419. $cb1 = new Channel_Buffer("schulhof");
  420. $cb2 = new Channel_Buffer("lehrerzimmer");
  421. $cb1->connect();
  422. $cb2->connect();
  423. // write some extra lines
  424. $cb1_idx = $cb1->get_cur_line_idx();
  425. $cb2_idx = $cb2->get_cur_line_idx();
  426. $cb1->put_line("1:4");
  427. $cb2->put_line("2:4");
  428. // get test lines and print them
  429. // first channel buffer
  430. // expect "1:4"
  431. $lines = $cb1->get_lines_since($cb1_idx);
  432. foreach ($lines as $l) {
  433. print $cb1->get_name().": $l $nl";
  434. }
  435. // second channel buffer
  436. // expect "2:4"
  437. $lines = $cb2->get_lines_since($cb2_idx);
  438. foreach ($lines as $l) {
  439. print $cb2->get_name().": $l $nl";
  440. }
  441. // destroy channel buffers (channel is removed)
  442. $cb1->destroy();
  443. $cb2->destroy();
  444. }
  445. }
  446. ?>

Documentation generated on Tue, 29 Jun 2004 14:41:51 +0200 by phpDocumentor 1.3.0RC3