/
InMemoryPasteService.php
119 lines (105 loc) · 2.74 KB
/
InMemoryPasteService.php
1
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
<?php
namespace TwoBulb\PasteBundle\Service;
class InMemoryPasteService implements PasteService {
/** @var \Symfony\Bridge\Monolog\Logger */
private $log;
private $lockfile;
private $shmid;
private $shm_key = 0xBABA1792;
private $shm_size;
private function lock() {
if (!flock($this->lockfile, LOCK_EX))
throw new \Exception('error locking');
}
private function unlock() {
if (!flock($this->lockfile, LOCK_UN))
throw new \Exception('error unlocking');
}
private function persist() {
$data = serialize($this->db);
$result = shmop_write($this->shmid, $data, 0);
if (FALSE === $result)
throw new \Exception('error writing shared memory');
}
public function __construct($log) {
$this->log = $log;
$this->lockfile = tmpfile();
$this->lock();
$this->shm_size = 10 * 1024 * 1024;
$this->shmid = @shmop_open($this->shm_key, "a", 0666, 0);
if ($this->shmid) {
shmop_close($this->shmid);
$this->shmid = shmop_open($this->shm_key, "c", 0666, $this->shm_size);
$data = shmop_read($this->shmid, 0, $this->shm_size);
try {
$this->db = unserialize($data);
} catch (\Exception $e) {
throw new \Exception('unserialize failed. Key already in use?', 500, $e);
}
} else {
$this->shmid = shmop_open($this->shm_key, "c", 0666, $this->shm_size);
$this->db = array();
$this->persist();
}
$this->shmid = $this->shmid;
$this->unlock();
}
public function __destruct() {
$this->log->debug("InMemoryPasteService::__destruct()");
if (!fclose($this->lockfile))
$this->log->warn('failed to close lockfile');
shmop_close($this->shmid);
}
/**
* @return array
*/
public function fetchMany($limit, $offset) {
$this->lock();
$p = $this->db;
$this->unlock();
return $p;
}
/**
* @param string $id
* @return Paste
*/
public function fetchOne($id) {
$this->lock();
$p = $this->db[$id];
$this->unlock();
return $p;
}
private function generateId() {
if (count($this->db) < 1) {
return 1;
} else {
return max(array_keys($this->db)) + 1;
}
}
/**
* @param Paste $paste
* @return Paste just-stored object
*/
public function store(Paste $paste) {
$this->lock();
$id = $this->generateId();
$paste->setId($id);
$paste->setCreatedTimestamp(new \DateTime());
$this->db[$paste->getId()] = $paste;
$this->persist();
$this->unlock();
return $paste;
}
public function deleteAll() {
$this->lock();
$this->db = array();
$this->persist();
$this->unlock();
}
public function deleteOne($id) {
$this->lock();
unset($this->db[$id]);
$this->persist();
$this->unlock();
}
}