PageRenderTime 26ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/b2b/core/include/mapfile.php

http://phpfor.googlecode.com/
PHP | 374 lines | 324 code | 40 blank | 10 comment | 49 complexity | 38d107d088a9ab91e743d1d3884cc839 MD5 | raw file
  1. <?php
  2. define('DF_BEGIN',0);
  3. define('DF_END',1);
  4. define('DF_SIZE',2);
  5. define('DF_MTIME',3);
  6. define('DF_INLINE_DATA',4);
  7. class mapfile{
  8. var $hs = null; //headerSize
  9. var $bs = 512; //blockSize
  10. var $is = 128; //introSize
  11. var $seq = 0;
  12. var $maxsize = 15728640; //max 15m
  13. var $sparse = true; //????
  14. var $auto_remove_eldest_entry = true;
  15. function mapfile(){
  16. $this->infoKey = array('hs'=>1,'is'=>1,'bs'=>1,'seq'=>1,'maxsize'=>1);
  17. $this->pid = mt_rand(0,32768);
  18. $this->now = time();
  19. }
  20. function set($key,$data){
  21. $data = serialize($data);
  22. if($this->mainFile){
  23. $slen = strlen($data);
  24. $bs = intval(ceil($slen/$this->bs));
  25. $this->header['used'][$key][DF_MTIME] = $this->now;
  26. $this->header['used'][$key][DF_SIZE] = $slen;
  27. if(isset($this->header['used'][$key])){
  28. $space = $this->header['used'][$key][DF_END] - $this->header['used'][$key][DF_BEGIN];
  29. if($space >= $bs){
  30. fseek($this->handle,$this->hs + $this->is + $this->header['used'][$key][DF_BEGIN]*$this->bs);
  31. fputs($this->handle,$data);
  32. if($space>$bs){
  33. $oldEnd = $this->header['used'][$key][DF_END];
  34. $this->header['used'][$key][DF_END] = $this->header['used'][$key][DF_BEGIN] + $bs;
  35. $this->_freespace($this->header['used'][$key][DF_END],$oldEnd);
  36. }
  37. $this->log('???????@'.$this->header['used'][$key][DF_BEGIN].'-'.$this->header['used'][$key][DF_END]);
  38. return true;
  39. }else{
  40. $this->_freespace($this->header['used'][$key][DF_BEGIN],$this->header['used'][$key][DF_END]);
  41. }
  42. }
  43. if($this->header['free'] && !$this->_freeSets){
  44. foreach($this->header['free'] as $k=>$v){
  45. $this->_freeSets[$v-$k][$k] = $k;
  46. }
  47. ksort($this->_freeSets);
  48. }
  49. if(is_array($this->_freeSets))
  50. foreach($this->_freeSets as $size=>$freeList){
  51. if($size>=$bs){
  52. if(count($this->_freeSets[$size])>0){
  53. $pos = current($this->_freeSets[$size]);
  54. unset($this->_freeSets[$size][$pos]);
  55. fseek($this->handle,$this->hs + $this->is + $pos*$this->bs);
  56. fputs($this->handle,$data);
  57. $this->header['used'][$key][DF_BEGIN] = $pos;
  58. $this->header['used'][$key][DF_END] = $pos+$bs;
  59. $this->log('????@'.$pos.'-'.$this->header['free'][$pos]);
  60. $this->_alloc($pos,$bs);
  61. return true;
  62. }else{
  63. unset($this->_freeSets[$size]);
  64. }
  65. }
  66. }
  67. $begin = $this->seq;
  68. if((($begin + $bs)*$this->bs + $this->hs + $this->is) > $this->maxsize){
  69. //todo: lru
  70. if(false && $this->auto_remove_eldest_entry){
  71. if($free = $this->remove_eldest_entry($bs)){
  72. $begin = $free[DF_BEGIN];
  73. $this->_freespace($free[DF_BEGIN]+$bs,$free[DF_END]);
  74. }else{
  75. unset($this->header['used'][$key]);
  76. $this->error('No enough dfile-space @'.$this->file.' when alloc '.$bs*$this->hs,E_USER_WARNING);
  77. return false;
  78. }
  79. }else{
  80. unset($this->header['used'][$key]);
  81. $this->error('No enough dfile-space @'.$this->file.' when alloc '.$bs*$this->hs,E_USER_WARNING);
  82. return false;
  83. }
  84. }else{
  85. $this->seq+=$bs;
  86. }
  87. fseek($this->handle,$this->hs + $this->is + $begin*$this->bs);
  88. fputs($this->handle,$data);
  89. $this->log('??@'.$begin);
  90. $this->header['used'][$key][DF_BEGIN] = $begin;
  91. $this->header['used'][$key][DF_END] = $begin+$bs;
  92. return true;
  93. }else{
  94. return true;
  95. }
  96. }
  97. function remove_eldest_entry($requireSize){
  98. $s = $requireSize*$this->bs;
  99. foreach($this->header['used'] as $k=>$v){
  100. if($v[DF_SIZE]>=$s){
  101. $this->delete($k);
  102. return $v;
  103. }
  104. }
  105. return false;
  106. }
  107. function log($message){
  108. if($this->log_func){
  109. call_user_func_array($this->log_func,array($message));
  110. }
  111. }
  112. function delete($key){
  113. if($this->mainFile){
  114. $this->log('??'.$key);
  115. if($this->_freespace($this->header['used'][$key][DF_BEGIN],$this->header['used'][$key][DF_END])){
  116. unset($this->header['used'][$key]);
  117. return true;
  118. }else{
  119. return false;
  120. }
  121. }else{
  122. $this->tmpHeader['del'][$key] = $key;
  123. $this->log('???delete');
  124. }
  125. }
  126. function _alloc($pos,$blocks){
  127. $this->log('??@'.$pos.'-'.($pos+$blocks));
  128. if(isset($this->header['free'][$pos])){
  129. if($this->header['free'][$pos]==$pos+$blocks){
  130. $oldEnd = $this->header['free'][$pos];
  131. unset($this->header['free'][$pos]);
  132. unset($this->freeSpace[$oldEnd]);
  133. }elseif($this->header['free'][$pos]>$pos+$blocks){
  134. $oldEnd = $this->header['free'][$pos];
  135. unset($this->header['free'][$pos]);
  136. $this->header['free'][$pos+$blocks] = $oldEnd;
  137. $this->freeSpace[$oldEnd] = $pos+$blocks;
  138. $this->log('??????@'.($pos + $blocks).'-'.($oldEnd));
  139. $this->_freeSets[$oldEnd - $pos - $blocks][$pos+$blocks] = $pos+$blocks;
  140. return true;
  141. }else{
  142. return false;
  143. }
  144. }else{
  145. return false;
  146. }
  147. }
  148. /**
  149. * _freespace
  150. * ?????????
  151. *
  152. * @param mixed $begin
  153. * @param mixed $end
  154. * @access public
  155. * @return void
  156. */
  157. function _freespace($begin,$end){
  158. if($end>$begin){
  159. $this->log('????'.$begin.'-'.$end);
  160. if(isset($this->freeSpace[$begin])){
  161. $early_begin = $this->freeSpace[$begin];
  162. $this->log('??'.$this->freeSpace[$begin].'-'.$begin.','.$begin.'-'.$end);
  163. if($this->_freeSets){
  164. $this->log('??_freeSets['.($begin-$this->freeSpace[$begin]).']['.$this->freeSpace[$begin].']');
  165. if($this->_freeSets[$begin-$this->freeSpace[$begin]][$this->freeSpace[$begin]]){
  166. $this->log('??');
  167. unset($this->_freeSets[$begin-$this->freeSpace[$begin]][$this->freeSpace[$begin]]);
  168. }else{
  169. $this->log('??');
  170. }
  171. }
  172. unset($this->header['free'][$this->freeSpace[$begin]]);
  173. unset($this->freeSpace[$begin]);
  174. $begin = $early_begin;
  175. }
  176. if(isset($this->header['free'][$end])){
  177. $final_end = $this->header['free'][$end];
  178. $this->log('??'.$begin.'-'.$end.','.$end.'-'.$this->header['free'][$end]);
  179. if($this->_freeSets){
  180. $this->log('??_freeSets['.($final_end-$end).']['.$end.']');
  181. if($this->_freeSets[$final_end-$end][$end]){
  182. $this->log('??');
  183. unset($this->_freeSets[$final_end-$end][$end]);
  184. }else{
  185. $this->log('??');
  186. }
  187. }
  188. unset($this->freeSpace[$final_end]);
  189. unset($this->header['free'][$end]);
  190. $end = $final_end;
  191. }
  192. $this->header['free'][$begin] = $end;
  193. $this->freeSpace[$end] = $begin;
  194. return true;
  195. }
  196. }
  197. function error($msg,$error_code){
  198. if($this->error_handle){
  199. call_user_func_array($this->error_handle,func_get_args());
  200. }else{
  201. trigger_error($msg,$error_code);
  202. }
  203. }
  204. function &get($key){
  205. if(isset($this->header['used'][$key])){
  206. $tmp = $this->header['used'][$key];
  207. unset($this->header['used'][$key]);
  208. $this->header['used'][$key] = $tmp;
  209. unset($tmp);
  210. fseek($this->handle,$this->hs + $this->is + $this->header['used'][$key][DF_BEGIN]*$this->bs);
  211. $orgData = fread($this->handle, $this->header['used'][$key][DF_SIZE]);
  212. if(!($data = unserialize($orgData))){
  213. fseek($this->handle,$this->hs + $this->is + $this->header['used'][$key][DF_BEGIN]*$this->bs);
  214. $orgData = fread($this->handle, $this->header['used'][$key][DF_SIZE]+20);
  215. $this->error('data can\'t unserialize('.$orgData.')',E_USER_WARNING);
  216. $this->clear(); //?????????????
  217. return false;
  218. }else{
  219. return $data;
  220. }
  221. }else{
  222. return false;
  223. }
  224. }
  225. function workat($mapfile){
  226. register_shutdown_function(array(&$this,'close'));
  227. if(file_exists($mapfile)){
  228. $this->file = realpath($mapfile);
  229. if(!file_exists($mapfile.'.lock') || ($this->now-filemtime($mapfile)>60)){
  230. $this->mainFile = true;
  231. touch($mapfile.'.lock');
  232. $this->handle = fopen($mapfile,'r+');
  233. $this->log('??? open');
  234. }else{
  235. $this->handle = fopen($mapfile,'r');
  236. $this->mainFile = false;
  237. }
  238. $data = fread($this->handle,$this->is);
  239. if($info = unserialize(trim($data))){
  240. foreach($info as $k=>$v){
  241. if($this->infoKey[$k]) $this->$k = $v;
  242. }
  243. }
  244. if(fseek($this->handle,$this->is)!=-1){
  245. if(!($this->header = unserialize(trim(fread($this->handle,$this->hs))))){
  246. $this->clear();
  247. }
  248. if(is_array($this->header['free']))
  249. $this->freeSpace = array_flip($this->header['free']);
  250. }
  251. return true;
  252. }elseif($this->createMapFile($mapfile)){
  253. touch($mapfile.'.lock');
  254. $this->file = realpath($mapfile);
  255. $this->mainFile = true;
  256. $this->log('??? ????');
  257. return true;
  258. }else{
  259. $this->log('?????????');
  260. return false;
  261. }
  262. }
  263. function clear(){
  264. $this->doNothing = true;
  265. if($this->mainFile){
  266. if($this->handle){
  267. fclose($this->handle);
  268. }
  269. }else{
  270. unlink($this->file.'.lock');
  271. }
  272. return $this->createMapFile($this->file);
  273. }
  274. function createMapFile($mapfile){
  275. if(!$this->hs){
  276. $this->hs = intval($this->maxsize/10);
  277. }
  278. $info = array();
  279. foreach(get_object_vars($this) as $k=>$v){
  280. if(isset($this->infoKey[$k])){
  281. $info[$k] = $v;
  282. }
  283. }
  284. if(file_put_contents($mapfile,serialize($info))){
  285. $this->handle = fopen($mapfile,'r+');
  286. if($this->sparse){
  287. fseek($this->handle,$this->maxsize-1);
  288. fputs($this->handle,"\0");
  289. }
  290. return true;
  291. }else{
  292. return false;
  293. }
  294. }
  295. function close(){
  296. if($this->doNothing)return;
  297. if($this->mainFile && file_exists($this->file.'.lock')){
  298. $info = array();
  299. foreach($this->infoKey as $k=>$v){
  300. $info[$k] = $this->$k;
  301. }
  302. $head = serialize($this->header);
  303. if(($headLength=strlen($head))>$this->hs){
  304. $this->clear(); //???????????inode?
  305. $this->error('No enough dfile-header @'.$this->file.' ,want/free:'.$headLength.'/'.$this->hs,E_USER_WARNING);
  306. }else{
  307. fseek($this->handle,$this->is);
  308. fputs($this->handle,$head);
  309. fseek($this->handle,0);
  310. fputs($this->handle,serialize($info));
  311. }
  312. fclose($this->handle);
  313. unlink($this->file.'.lock');
  314. $this->log('??? close');
  315. }
  316. }
  317. function picture(){
  318. $pic = array();
  319. if(is_array($this->header['free']))
  320. foreach($this->header['free'] as $begin=>$end){
  321. $pic[$begin] = $this->_pic_block($end-$begin,'free',$begin.'-'.$end);
  322. }
  323. if(is_array($this->header['used']))
  324. foreach($this->header['used'] as $key=>$data){
  325. $pic[$data[DF_BEGIN]] = $this->_pic_block($data[DF_END]-$data[DF_BEGIN],'full',$key.'@'.$data[DF_BEGIN].'-'.$data[DF_END]);
  326. }
  327. ksort($pic);
  328. return '<style>.full{background-color:red;float:left;border-right:1px solid #fff}.free{background-color:green;float:left;border-right:1px solid #fff}</style><div style="width:500px">'.implode("\n",$pic).'</div>';
  329. }
  330. function _pic_block($width,$cls,$msg){
  331. return '<div onclick="alert(\''.htmlspecialchars($msg).'\')" style="width:'.($width*5).'px" class="'.$cls.'">&nbsp</div>';
  332. }
  333. }
  334. ?>