Link to Trubanc 1.0b1 announcement
[loomclient.git] / GDBM.php
blob9841af38fc3cd3587642e4da5c738f72c300bc11
1 <?php
3 // GDBM class with live compression
5 class GDBM {
7 var $oldfile; // The name of the "Old" file
8 var $newfile; // The name of the "New" file
9 var $oldr; // Resource pointer for $oldfile
10 var $newr; // Resource pointer for $newfile
11 var $copycount; // Number of keys to copy per access
12 var $error; // error string for last operation
14 function GDBM($oldfile, $newfile, $copycount=20, $handler="gdbm") {
15 $this->oldfile = $oldfile;
16 $this->newfile = $newfile;
17 $this->copycount = $copycount;
18 $this->handler = $handler;
20 $oldr = dba_open($oldfile, 'cl', $handler);
22 if (!$oldr) {
23 $this->error = "Could not open old database";
24 return;
27 $this->oldr = $oldr;
29 if ($newfile == '') {
30 $this->newfile = false;
31 $this->newr = false;
32 } else {
33 if (file_exists($newfile)) {
34 $this->newr = dba_open($newfile, 'wl', $handler);
35 } else $this->newr = false;
39 // Get the value for a key.
40 // If it's in the new database, return that value.
41 // If the deleted key is in the new database, return false.
42 // Otherwise, return the value in the old databae.
43 function get($key) {
44 $value = false;
45 if ($this->newr) {
46 $this->copysome(true);
47 if ($this->newr) $value = dba_fetch($key, $this->newr);
49 if (!$value) $value = dba_fetch($key, $this->oldr);
50 return $value;
53 // Replace or set the value of $key to $value.
54 // If $value is blank or false, delete $key from the database
55 // Return the new value
56 function put($key, $value) {
57 if ($value == '' || !$value) {
58 // Blank or false value = delete the key
59 dba_delete($key, $this->oldr);
60 if ($this->newr) {
61 dba_delete($key, $this->newr);
62 $this->copysome(true);
64 } else {
65 if ($this->newr) {
66 dba_replace($key, $value, $this->newr);
67 dba_delete($key, $this->oldr);
68 $this->copysome(true);
69 } else {
70 dba_replace($key, $value, $this->oldr);
73 return $value;
76 // Create a new database, if there isn't one, and start copying to it
77 function startCopying() {
78 if (!$this->newr && $this->newfile) {
79 $this->newr = dba_open($this->newfile, 'cl', $this->handler);
81 return $this->newr;
84 // True if we're currently copying old to new
85 function isCopying() {
86 return $this->newr;
89 // Finish copying old to new, delete old, rename new to old, and reopen
90 // Do NOT start copying again.
91 function finishCopying() {
92 while ($this->newr) $this->copysome(false);
95 // Close the database(s). Finish copying first if $finish_copying is true
96 function close($finish_copying=false) {
97 if ($finish_copying) $this->finishCopying();
98 if ($this->oldr) {
99 dba_close($this->oldr);
100 $this->oldr = false;
102 if ($this->newr) {
103 dba_close($this->newr);
104 $this->newr = false;
108 // Reopen the database after a close.
109 // Does nothing if alredy open
110 function reopen() {
111 if (!$this->oldr) {
112 $this->oldr = dba_open($this->oldfile, 'wl', $this->handler);
113 if (!$this->oldr) $this->error = "Could not reopen old file";
115 return $this->oldr;
118 // Return the message for the last error that happened, and clear it
119 function errorMessage() {
120 $res = $this->error;
121 $this->error = '';
122 return $res;
125 // Copy $this->copycount keys from old to new database
126 function copysome($reopen) {
127 if ($this->newr) {
128 for ($i=0; $i<$this->copycount; $i++) {
129 $key = dba_firstkey($this->oldr);
130 if ($key) $this->copyone($key);
131 else {
132 // We're done copying.
133 $this->flipDBs($reopen);
134 return;
140 // Copy one key from old to new database
141 function copyone($key) {
142 if ($this->newr) {
143 if (!dba_fetch($key, $this->newr)) {
144 $value = dba_fetch($key, $this->oldr);
145 if ($value) dba_replace($key, $value, $this->newr);
147 dba_delete($key, $this->oldr);
151 // Delete the old database, and rename new to old
152 function flipDBs($reopen) {
153 $this->close(false);
154 $oldsize = filesize($this->oldfile);
155 $newsize = filesize($this->newfile);
156 $this->error = "old size: $oldsize, new size: $newsize";
157 if (unlink($this->oldfile)) {
158 if (rename($this->newfile, $this->oldfile)) {
159 if ($reopen) $this->reopen();
160 } else $this->error = "Could not rename new file to old file";
161 } else $this->error = "Could not unlink old file";
166 // Test code. Uncomment to run.
168 if (file_exists('old.db')) unlink('old.db');
169 if (file_exists('new.db')) unlink('new.db');
170 $db = new GDBM('old.db', 'new.db', 1);
171 $cnt = 99;
172 $loops = 10;
173 for ($i=1; $i<=$cnt; $i++) {
174 $db->put($i, $i);
176 $db->startCopying();
177 for ($j=0; $j<$loops; $j++) {
178 for ($i=1; $i<=$cnt; $i++) {
179 if (($j % 2) == 1 && ($i % 10) == 3) $db->put($i, '');
180 else $db->put($i, 10 * $db->get($i));
181 if (!$db->isCopying()) {
182 echo "Restarting copying, j=$j, i=$i\n";
183 echo " " . $db->errorMessage() . "\n";
184 $db->startCopying();
188 for ($i=1; $i<=$cnt; $i++) {
189 echo "$i: " . $db->get($i) . "\n";
190 if (!$db->isCopying()) $db->startCopying();
192 $db->close(true);
195 /* ***** BEGIN LICENSE BLOCK *****
196 * Version: MPL 1.1/GPL 2.0/LGPL 2.1/Apache 2.0
198 * The contents of this file are subject to the Mozilla Public License Version
199 * 1.1 (the "License"); you may not use this file except in compliance with
200 * the License. You may obtain a copy of the License at
201 * http://www.mozilla.org/MPL/
203 * Software distributed under the License is distributed on an "AS IS" basis,
204 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
205 * for the specific language governing rights and limitations under the
206 * License.
208 * The Original Code is LoomClient PHP library
210 * The Initial Developer of the Original Code is
211 * Bill St. Clair.
212 * Portions created by the Initial Developer are Copyright (C) 2008
213 * the Initial Developer. All Rights Reserved.
215 * Contributor(s):
216 * Bill St. Clair <bill@billstclair.com>
218 * Alternatively, the contents of this file may be used under the
219 * terms of the GNU General Public License Version 2 or later (the
220 * "GPL"), the GNU Lesser General Public License Version 2.1 or later
221 * (the "LGPL"), or The Apache License Version 2.0 (the "AL"), in
222 * which case the provisions of the GPL, LGPL, or AL are applicable
223 * instead of those above. If you wish to allow use of your version of
224 * this file only under the terms of the GPL, the LGPL, or the AL, and
225 * not to allow others to use your version of this file under the
226 * terms of the MPL, indicate your decision by deleting the provisions
227 * above and replace them with the notice and other provisions
228 * required by the GPL or the LGPL. If you do not delete the
229 * provisions above, a recipient may use your version of this file
230 * under the terms of any one of the MPL, the GPL the LGPL, or the AL.
231 ****** END LICENSE BLOCK ***** */