1: <?php
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: class Horde_Lock_Sql extends Horde_Lock
32: {
33: 34: 35: 36: 37:
38: private $_db;
39:
40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51:
52: public function __construct($params = array())
53: {
54: if (!isset($params['db'])) {
55: throw new Horde_Lock_Exception('Missing db parameter.');
56: }
57: $this->_db = $params['db'];
58: unset($params['db']);
59:
60: $params = array_merge(array(
61: 'table' => 'horde_locks'
62: ), $params);
63:
64: parent::__construct($params);
65:
66: 67:
68: if (rand(0, 999) == 0) {
69: register_shutdown_function(array($this, 'doGC'));
70: }
71: }
72:
73: 74: 75: 76: 77:
78: public function getLockInfo($lockid)
79: {
80: $now = time();
81: $sql = 'SELECT lock_id, lock_owner, lock_scope, lock_principal, ' .
82: 'lock_origin_timestamp, lock_update_timestamp, ' .
83: 'lock_expiry_timestamp, lock_type FROM ' . $this->_params['table'] .
84: ' WHERE lock_id = ? AND lock_expiry_timestamp >= ?';
85: $values = array($lockid, $now);
86:
87: try {
88: return $this->_db->selectOne($sql, $values);
89: } catch (Horde_Db_Exception $e) {
90: throw new Horde_Lock_Exception($e);
91: }
92: }
93:
94: 95: 96: 97: 98: 99:
100: public function getLocks($scope = null, $principal = null, $type = null)
101: {
102: $now = time();
103: $sql = 'SELECT lock_id, lock_owner, lock_scope, lock_principal, ' .
104: 'lock_origin_timestamp, lock_update_timestamp, ' .
105: 'lock_expiry_timestamp, lock_type FROM ' .
106: $this->_params['table'] . ' WHERE lock_expiry_timestamp >= ?';
107: $values = array($now);
108:
109:
110: if (!empty($principal)) {
111: $sql .= ' AND lock_principal = ?';
112: $values[] = $principal;
113: }
114: if (!empty($scope)) {
115: $sql .= ' AND lock_scope = ?';
116: $values[] = $scope;
117: }
118: if (!empty($type)) {
119: $sql .= ' AND lock_type = ?';
120: $values[] = $type;
121: }
122:
123: try {
124: $result = $this->_db->selectAll($sql, $values);
125: } catch (Horde_Db_Exception $e) {
126: throw new Horde_Lock_Exception($e);
127: }
128:
129: $locks = array();
130: foreach ($result as $row) {
131: $locks[$row['lock_id']] = $row;
132: }
133:
134: return $locks;
135: }
136:
137: 138: 139: 140: 141:
142: public function resetLock($lockid, $extend)
143: {
144: $now = time();
145:
146: if (!$this->getLockInfo($lockid)) {
147: return false;
148: }
149:
150: $expiry = $now + $extend;
151: $sql = 'UPDATE ' . $this->_params['table'] . ' SET ' .
152: 'lock_update_timestamp = ?, lock_expiry_timestamp = ? ' .
153: 'WHERE lock_id = ?';
154: $values = array($now, $expiry, $lockid);
155:
156: try {
157: $this->_db->update($sql, $values);
158: } catch (Horde_Db_Exception $e) {
159: throw new Horde_Lock_Exception($e);
160: }
161:
162: return true;
163: }
164:
165: 166: 167: 168: 169: 170:
171: public function setLock($requestor, $scope, $principal,
172: $lifetime = 1, $type = Horde_Lock::TYPE_SHARED)
173: {
174: $oldlocks = $this->getLocks($scope, $principal, Horde_Lock::TYPE_EXCLUSIVE);
175:
176: if (count($oldlocks) != 0) {
177:
178: if ($this->_logger) {
179: $this->_logger->log(sprintf('Lock requested for %s denied due to existing exclusive lock.', $principal), 'NOTICE');
180: }
181: return false;
182: }
183:
184: $lockid = (string)new Horde_Support_Uuid();
185:
186: $now = time();
187: $expiration = $now + $lifetime;
188: $sql = 'INSERT INTO ' . $this->_params['table'] . ' (lock_id, lock_owner, lock_scope, lock_principal, lock_origin_timestamp, lock_update_timestamp, lock_expiry_timestamp, lock_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)';
189: $values = array($lockid, $requestor, $scope, $principal, $now, $now,
190: $expiration, $type);
191:
192: try {
193: $this->_db->insert($sql, $values);
194: } catch (Horde_Db_Exception $e) {
195: throw new Horde_Lock_Exception($e);
196: }
197:
198: if ($this->_logger) {
199: $this->_logger->log(sprintf('Lock %s set successfully by %s in scope %s on "%s"', $lockid, $requestor, $scope, $principal), 'DEBUG');
200: }
201:
202: return $lockid;
203: }
204:
205: 206: 207: 208: 209:
210: public function clearLock($lockid)
211: {
212: if (empty($lockid)) {
213: throw new Horde_Lock_Exception('Must supply a valid lock ID.');
214: }
215:
216:
217:
218:
219: $sql = 'DELETE FROM ' . $this->_params['table'] . ' WHERE lock_id = ?';
220: $values = array($lockid);
221:
222: try {
223: $this->_db->delete($sql, $values);
224: } catch (Horde_Db_Exception $e) {
225: throw new Horde_Lock_Exception($e);
226: }
227:
228: if ($this->_logger) {
229: $this->_logger->log(sprintf('Lock %s cleared successfully.', $lockid), 'DEBUG');
230: }
231:
232: return true;
233: }
234:
235: 236: 237:
238: public function doGC()
239: {
240: $now = time();
241: $query = 'DELETE FROM ' . $this->_params['table'] . ' WHERE ' .
242: 'lock_expiry_timestamp < ? AND lock_expiry_timestamp != 0';
243: $values = array($now);
244:
245: try {
246: $result = $this->_db->delete($query, $values);
247: if ($this->_logger) {
248: $this->_logger->log(sprintf('Lock garbage collection cleared %d locks.', $result), 'DEBUG');
249: }
250: } catch (Horde_Db_Exception $e) {}
251: }
252:
253: }
254: