Add ##loom irc channel
[loomclient.git] / GDBM.php
bloba70c98f8a7a5d0ea4edf104b30f156d47ae674a8
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 // Copyright 2008 Bill St. Clair
197 // Licensed under the Apache License, Version 2.0 (the "License");
198 // you may not use this file except in compliance with the License.
199 // You may obtain a copy of the License at
201 // http://www.apache.org/licenses/LICENSE-2.0
203 // Unless required by applicable law or agreed to in writing, software
204 // distributed under the License is distributed on an "AS IS" BASIS,
205 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
206 // See the License for the specific language governing permissions
207 // and limitations under the License.