Clover coverage report -
Coverage timestamp: Sun Nov 1 2009 23:08:24 UTC
file stats: LOC: 332   Methods: 31
NCLOC: 211   Classes: 4
 
 Source file Conditionals Statements Methods TOTAL
BTreeFiler.java 94.4% 92.6% 90.3% 92.3%
coverage coverage
 1    /*
 2    * Licensed to the Apache Software Foundation (ASF) under one or more
 3    * contributor license agreements. See the NOTICE file distributed with
 4    * this work for additional information regarding copyright ownership.
 5    * The ASF licenses this file to You under the Apache License, Version 2.0
 6    * (the "License"); you may not use this file except in compliance with
 7    * the License. You may obtain a copy of the License at
 8    *
 9    * http://www.apache.org/licenses/LICENSE-2.0
 10    *
 11    * Unless required by applicable law or agreed to in writing, software
 12    * distributed under the License is distributed on an "AS IS" BASIS,
 13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14    * See the License for the specific language governing permissions and
 15    * limitations under the License.
 16    *
 17    * $Id: BTreeFiler.java 712571 2008-11-09 22:00:06Z natalia $
 18    */
 19   
 20    package org.apache.xindice.core.filer;
 21   
 22    import org.apache.commons.logging.Log;
 23    import org.apache.commons.logging.LogFactory;
 24    import org.apache.xindice.core.DBException;
 25    import org.apache.xindice.core.FaultCodes;
 26    import org.apache.xindice.core.data.Key;
 27    import org.apache.xindice.core.data.Record;
 28    import org.apache.xindice.core.data.RecordSet;
 29    import org.apache.xindice.core.data.Value;
 30   
 31    import java.io.DataInput;
 32    import java.io.DataOutput;
 33    import java.io.File;
 34    import java.io.IOException;
 35    import java.io.RandomAccessFile;
 36    import java.util.ArrayList;
 37    import java.util.HashMap;
 38    import java.util.Iterator;
 39    import java.util.List;
 40   
 41    /**
 42    * BTreeFiler is a Filer implementation based on the BTree class.
 43    *
 44    * <br>
 45    * BTreeFiler has folowing configuration attributes:
 46    * <ul>
 47    * <li><strong>pagesize</strong>: Size of the page used by the filer.
 48    * Default page size is 4096 bytes. This parameter can be set only
 49    * before paged file is created. Once it is created, this parameter
 50    * can not be changed.</li>
 51    * <li><strong>pagecount</strong>: Number of pages filer will be created
 52    * with.</li>
 53    * <li><strong>maxkeysize</strong>: Maximum allowed size of the key.
 54    * Default maximum key size is 256 bytes.</li>
 55    * <li><strong>max-descriptors</strong>: Defines maximum amount of
 56    * simultaneously opened file descriptors this paged file can have.
 57    * Several descriptors are needed to provide multithreaded access
 58    * to the underlying file. Too large number will limit amount of
 59    * collections you can open. Default value is 16
 60    * (DEFAULT_DESCRIPTORS_MAX).</li>
 61    * </ul>
 62    *
 63    * @version $Revision: 712571 $, $Date: 2008-11-09 22:00:06 +0000 (Sun, 09 Nov 2008) $
 64    */
 65    public class BTreeFiler extends BTree
 66    implements Filer {
 67   
 68    private static final Log log = LogFactory.getLog(BTreeFiler.class);
 69   
 70    /**
 71    * Record page status
 72    */
 73    protected static final byte RECORD = 20;
 74   
 75   
 76    private BTreeFilerHeader fileHeader;
 77   
 78   
 79  1301 public BTreeFiler() {
 80  1301 super();
 81  1301 fileHeader = (BTreeFilerHeader) getFileHeader();
 82    }
 83   
 84  1301 public void setLocation(File root, String location) {
 85  1301 setFile(new File(root, location + ".tbl"));
 86    }
 87   
 88  20 public String getName() {
 89  20 return "BTreeFiler";
 90    }
 91   
 92  44231 public Record readRecord(Key key) throws DBException {
 93  44231 return readRecord(key, false);
 94    }
 95   
 96  46194 public Record readRecord(Key key, boolean metaOnly) throws DBException {
 97  46194 if (key == null || key.getLength() == 0) {
 98  8 return null;
 99    }
 100   
 101  46186 checkOpened();
 102  46186 try {
 103  46186 long pos = findValue(key);
 104  46186 if (pos == VALUE_DOES_NOT_EXIST) {
 105  8995 return null;
 106    }
 107   
 108  37191 Page startPage = getPage(pos);
 109  37191 Value v = metaOnly ? null : readValue(startPage);
 110  37191 BTreeFilerPageHeader sph = (BTreeFilerPageHeader) startPage.getPageHeader();
 111   
 112  37191 HashMap meta = new HashMap(2, 1.5F);
 113  37191 meta.put(Record.CREATED, new Long(sph.getCreated()));
 114  37191 meta.put(Record.MODIFIED, new Long(sph.getModified()));
 115   
 116  37191 return new Record(key, v, meta);
 117    } catch (IOException e) {
 118  0 throw new FilerException(FaultCodes.DBE_CANNOT_READ,
 119    "Can't read record '" + key + "': " + e.getMessage(), e);
 120    }
 121    }
 122   
 123  13246 public Record writeRecord(Key key, Value value) throws DBException {
 124  13246 if (key == null || key.getLength() == 0) {
 125  2 throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Invalid key: null or empty");
 126    }
 127  13244 if (value == null) {
 128  1 throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Invalid value: null");
 129    }
 130   
 131  13243 checkOpened();
 132  13243 try {
 133  13243 long pos = addKey(key);
 134  13243 Page p = getPage(pos);
 135   
 136  13243 BTreeFilerPageHeader ph = (BTreeFilerPageHeader) p.getPageHeader();
 137  13242 long t = System.currentTimeMillis();
 138  13243 if (ph.getStatus() == UNUSED) {
 139  8206 ph.setCreated(t);
 140    }
 141  13243 ph.setModified(t);
 142  13243 ph.setStatus(RECORD);
 143   
 144  13243 writeValue(p, value);
 145  13243 flush();
 146   
 147  13243 HashMap meta = new HashMap(3);
 148  13243 meta.put(Record.CREATED, new Long(ph.getCreated()));
 149  13243 meta.put(Record.MODIFIED, new Long(t));
 150  13242 return new Record(key, value, meta);
 151   
 152    } catch (IOException e) {
 153    // FIXME: cleanup?
 154  0 throw new FilerException(FaultCodes.DBE_CANNOT_CREATE,
 155    "Can't write record '" + key + "': " + e.getMessage(), e);
 156    }
 157    }
 158   
 159  2981 public boolean deleteRecord(Key key) throws DBException {
 160  2981 if (key == null || key.getLength() == 0) {
 161  2 return false;
 162    }
 163   
 164  2979 checkOpened();
 165  2979 try {
 166  2979 long pos = removeValue(key);
 167  2979 if (pos == VALUE_DOES_NOT_EXIST) {
 168  235 return false;
 169    }
 170   
 171  2744 Page p = getPage(pos);
 172  2744 unlinkPages(p);
 173   
 174  2744 fileHeader.decRecordCount();
 175   
 176  2744 flush();
 177  2744 return true;
 178    } catch (IOException e) {
 179  0 throw new FilerException(FaultCodes.DBE_CANNOT_DROP,
 180    "Can't delete record '" + key + "': " + e.getMessage(), e);
 181    }
 182    }
 183   
 184  148 public long getRecordCount() throws DBException {
 185  148 checkOpened();
 186  148 return fileHeader.getRecordCount();
 187    }
 188   
 189  435 public RecordSet getRecordSet() throws DBException {
 190  435 checkOpened();
 191  435 return new BTreeFilerRecordSet();
 192    }
 193   
 194    /**
 195    * BTreeFilerRecordSet
 196    */
 197    private class BTreeFilerRecordSet implements RecordSet, BTreeCallback {
 198    private List keys = new ArrayList();
 199    private Iterator iter;
 200   
 201  435 public BTreeFilerRecordSet() throws DBException {
 202  435 try {
 203  435 query(null, this);
 204  435 iter = keys.iterator();
 205    } catch (IOException e) {
 206  0 throw new FilerException(FaultCodes.GEN_CRITICAL_ERROR,
 207    "Error generating RecordSet", e);
 208    }
 209    }
 210   
 211  42987 public synchronized boolean indexInfo(Value value, long pointer) {
 212  42987 keys.add(new Key(value));
 213  42987 return true;
 214    }
 215   
 216  42983 public synchronized Key getNextKey() {
 217  42983 return (Key) iter.next();
 218    }
 219   
 220  4 public synchronized Record getNextRecord() throws DBException {
 221  4 return readRecord((Key) iter.next(), false);
 222    }
 223   
 224  0 public synchronized Value getNextValue() throws DBException {
 225  0 return getNextRecord().getValue();
 226    }
 227   
 228  43421 public synchronized boolean hasMoreRecords() {
 229  43421 return iter.hasNext();
 230    }
 231    }
 232   
 233    ////////////////////////////////////////////////////////////////////
 234   
 235  1301 protected FileHeader createFileHeader() {
 236  1301 return new BTreeFilerHeader();
 237    }
 238   
 239  46819 protected PageHeader createPageHeader() {
 240  46819 return new BTreeFilerPageHeader();
 241    }
 242   
 243    /**
 244    * BTreeFilerHeader
 245    */
 246    private final class BTreeFilerHeader extends BTreeFileHeader {
 247    private long totalBytes;
 248   
 249  1301 public BTreeFilerHeader() {
 250    }
 251   
 252  2364 protected synchronized void read(RandomAccessFile raf) throws IOException {
 253  2364 super.read(raf);
 254  2364 totalBytes = raf.readLong();
 255    }
 256   
 257  17877 protected synchronized void write(RandomAccessFile raf) throws IOException {
 258  17877 super.write(raf);
 259  17877 raf.writeLong(totalBytes);
 260    }
 261   
 262    /** The total number of bytes in use by the file */
 263  25339 public synchronized void setTotalBytes(long totalBytes) {
 264  25339 this.totalBytes = totalBytes;
 265  25339 setDirty();
 266    }
 267   
 268    /** The total number of bytes in use by the file */
 269  0 public synchronized long getTotalBytes() {
 270  0 return totalBytes;
 271    }
 272    }
 273   
 274    /**
 275    * BTreeFilerPageHeader
 276    */
 277    private final class BTreeFilerPageHeader extends BTreePageHeader {
 278    private long created;
 279    private long modified;
 280   
 281  46819 public BTreeFilerPageHeader() {
 282    }
 283   
 284  0 public BTreeFilerPageHeader(DataInput dis) throws IOException {
 285  0 super(dis);
 286    }
 287   
 288  38383 public synchronized void read(DataInput dis) throws IOException {
 289  38383 super.read(dis);
 290   
 291  38383 if (getStatus() == UNUSED) {
 292  3 return;
 293    }
 294   
 295  38380 created = dis.readLong();
 296  38380 modified = dis.readLong();
 297    }
 298   
 299  27636 public synchronized void write(DataOutput dos) throws IOException {
 300  27636 super.write(dos);
 301  27636 dos.writeLong(created);
 302  27636 dos.writeLong(modified);
 303    }
 304   
 305  25339 public synchronized void setRecordLen(int recordLen) {
 306  25339 fileHeader.setTotalBytes((fileHeader.totalBytes - getRecordLen()) + recordLen);
 307  25339 super.setRecordLen(recordLen);
 308    }
 309   
 310    /** UNIX-time when this record was created */
 311  8206 public synchronized void setCreated(long created) {
 312  8206 this.created = created;
 313  8206 setDirty();
 314    }
 315   
 316    /** UNIX-time when this record was created */
 317  50434 public synchronized long getCreated() {
 318  50434 return created;
 319    }
 320   
 321    /** UNIX-time when this record was last modified */
 322  13243 public synchronized void setModified(long modified) {
 323  13243 this.modified = modified;
 324  13243 setDirty();
 325    }
 326   
 327    /** UNIX-time when this record was last modified */
 328  37191 public synchronized long getModified() {
 329  37191 return modified;
 330    }
 331    }
 332    }