1 21 package com.db4o.util.io; 22 23 import java.io.*; 24 import java.lang.reflect.*; 25 import java.nio.*; 26 import java.nio.channels.*; 27 import java.util.*; 28 29 import com.db4o.io.*; 30 31 import sun.nio.ch.*; 32 33 public class NIOFileAdapter extends IoAdapter { 34 private int hits=0; 35 private int misses=0; 36 37 private int _pageSize; 38 private FileChannel _channel; 39 private MappedByteBuffer _page; 40 private int _pageId; 41 private long _position; 42 private long _size; 43 private boolean _dirty; 44 private Map _id2Page; 45 private LinkedList _lruPages; 46 private int _lruLimit; 47 private RandomAccessFile _file; 48 49 public NIOFileAdapter(int pageSize,int lruLimit) { 50 _pageSize=pageSize; 51 _lruLimit=lruLimit; 52 } 53 54 private NIOFileAdapter(String filename,boolean lockFile,long initialLength,int pageSize,int lruLimit) throws IOException { 55 _pageSize=pageSize; 56 _file=new RandomAccessFile(filename, "rw"); 57 _channel=_file.getChannel(); 58 _size=_channel.size(); 59 _page=null; 60 _pageId=0; 61 _position=0; 62 _dirty=false; 63 _id2Page=new HashMap(); 64 _lruPages=new LinkedList(); 65 _lruLimit=lruLimit; 66 } 67 68 public void seek(long position) throws IOException { 69 _position=position; 70 } 71 72 public void close() throws IOException { 73 for (Iterator pageiter = _id2Page.values().iterator(); pageiter.hasNext();) { 74 MappedByteBuffer curpage = (MappedByteBuffer) pageiter.next(); 75 closePage(curpage); 76 } 77 _id2Page.clear(); 78 _lruPages.clear(); 79 _page=null; 80 _channel.close(); 81 _file.close(); 82 } 84 85 public void delete(String path) { 86 new File(path).delete(); 87 } 88 89 public boolean exists(String path){ 90 File existingFile = new File(path); 91 return existingFile.exists() && existingFile.length() > 0; 92 } 93 94 public long getLength() throws IOException { 95 return _size; 96 } 97 98 public int read(byte[] bytes, int length) throws IOException { 99 if(length<=0) { 100 return 0; 101 } 102 int alreadyRead=0; 103 int stillToRead=length; 104 while(stillToRead>0) { 105 forcePage(); 106 try { 107 _page.position(pageOffset(_position)); 108 } 109 catch(IllegalArgumentException exc) { 110 return -1; 111 } 112 int hereToRead=(int)min(_page.limit()-_page.position(),stillToRead); 113 if(hereToRead==0) { 114 break; 115 } 116 _page.get(bytes,alreadyRead,hereToRead); 117 stillToRead-=hereToRead; 118 alreadyRead+=hereToRead; 119 _position+=hereToRead; 120 } 121 return (alreadyRead>0 ? alreadyRead : -1); 122 } 123 124 public void write(byte[] bytes, int length) throws IOException { 125 if(length<=0) { 126 return; 127 } 128 if(_position+length>_size) { 129 _size=_position+length; 130 } 131 int alreadyWritten=0; 132 int stillToWrite=length; 133 while(stillToWrite>0) { 134 forcePage(); 135 int pageOffset=pageOffset(_position); 136 _page.limit((int)min(_pageSize,pageOffset+length)); 137 _page.position(pageOffset); 138 int hereToWrite=(int)min(_page.capacity()-_page.position(),stillToWrite); 139 _page.put(bytes,alreadyWritten,hereToWrite); 140 stillToWrite-=hereToWrite; 141 alreadyWritten+=hereToWrite; 142 _position+=hereToWrite; 143 _dirty=true; 144 } 145 } 146 147 public void sync() throws IOException { 148 } 150 151 private void internalSync(MappedByteBuffer page) { 152 if(_dirty&&page!=null) { 153 page.flip(); 154 page.force(); 155 } 156 } 157 158 public void unlock() { 159 } 160 161 public void lock() { 162 } 163 164 private MappedByteBuffer page(int pageId) throws IOException { 165 MappedByteBuffer page=_channel.map(FileChannel.MapMode.READ_WRITE,pagePosition(pageId),_pageSize); 166 page.limit(pageSize(pageId)); 167 return page; 168 } 169 170 private long pagePosition(int pageId) { 171 return (long)pageId*_pageSize; 172 } 173 174 private int pageSize(int pageId) throws IOException { 175 long sizeLeft=_size-pagePosition(pageId); 176 return (sizeLeft>_pageSize ? _pageSize : (int)sizeLeft); 177 } 178 179 private void forcePage() throws IOException { 180 int pageId=pageId(_position); 181 int pageOffset=pageOffset(_position); 182 Integer pageIdKey=new Integer (pageId); 183 if(_id2Page.containsKey(pageIdKey)) { 184 _lruPages.remove(pageIdKey); 185 _lruPages.addFirst(pageIdKey); 186 _page=(MappedByteBuffer)_id2Page.get(pageIdKey); 187 _page.limit(pageSize(pageId)); 188 hits++; 189 return; 190 } 191 closePage(); 192 loadPage(pageId,pageOffset); 193 if (_lruPages.size()==_lruLimit) { 194 Integer dropPageKey=(Integer )_lruPages.removeLast(); 195 MappedByteBuffer page=(MappedByteBuffer)_id2Page.remove(dropPageKey); 196 try { 197 Method unmap=FileChannelImpl.class.getDeclaredMethod("unmap",new Class []{MappedByteBuffer.class}); 198 unmap.setAccessible(true); 199 unmap.invoke(null,new Object []{page}); 200 } catch (Exception exc) { 201 exc.printStackTrace(); 202 } 203 } 204 Integer addedPageKey=new Integer (_pageId); 205 _id2Page.put(addedPageKey,_page); 206 _lruPages.addFirst(addedPageKey); 207 _dirty=false; 208 misses++; 209 } 210 211 private void closePage() throws IOException { 212 closePage(_page); 213 _page=null; 214 } 215 216 private void closePage(MappedByteBuffer page) throws IOException { 217 if(page!=null) { 218 internalSync(page); 219 } 220 } 221 222 private void loadPage(int pageId,int pageOffset) throws IOException { 223 _page=page(pageId); 224 _pageId=pageId; 225 _dirty=false; 226 } 227 228 private int pageId(long position) { 229 return (int)(position/_pageSize); 230 } 231 232 private int pageOffset(long position) { 233 return (int)(position%_pageSize); 234 } 235 236 private long min(long a,long b) { 237 return (a>b ? b : a); 238 } 239 240 private long max(long a,long b) { 241 return (a<b ? b : a); 242 } 243 244 public IoAdapter open(String path, boolean lockFile, long initialLength) throws IOException { 245 return new NIOFileAdapter(path,lockFile,initialLength,_pageSize,_lruLimit); 246 } 247 } 248 | Popular Tags |