Clover coverage report -
Coverage timestamp: Sun Aug 17 2008 23:05:14 GMT
file stats: LOC: 335   Methods: 31
NCLOC: 215   Classes: 4
 
 Source file Conditionals Statements Methods TOTAL
BTreeFiler.java 83.3% 90.6% 90.3% 89.7%
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 541516 2007-05-25 02:46:51Z vgritsenko $
 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: 541516 $, $Date: 2007-05-24 19:46:51 -0700 (Thu, 24 May 2007) $
 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  1295 public BTreeFiler() {
 80  1295 super();
 81  1295 fileHeader = (BTreeFilerHeader) getFileHeader();
 82    }
 83   
 84  1295 public void setLocation(File root, String location) {
 85  1295 setFile(new File(root, location + ".tbl"));
 86    }
 87   
 88  20 public String getName() {
 89  20 return "BTreeFiler";
 90    }
 91   
 92  22476 public Record readRecord(Key key) throws DBException {
 93  22476 return readRecord(key, false);
 94    }
 95   
 96  24439 public Record readRecord(Key key, boolean metaOnly) throws DBException {
 97  24439 if (key == null || key.getLength() == 0) {
 98  8 return null;
 99    }
 100   
 101  24431 checkOpened();
 102  24431 try {
 103  24431 long pos = findValue(key);
 104  15499 Page startPage = getPage(pos);
 105  15499 Value v = metaOnly ? null : readValue(startPage);
 106  15499 BTreeFilerPageHeader sph = (BTreeFilerPageHeader) startPage.getPageHeader();
 107   
 108  15499 HashMap meta = new HashMap(2, 1.5F);
 109  15499 meta.put(Record.CREATED, new Long(sph.getCreated()));
 110  15499 meta.put(Record.MODIFIED, new Long(sph.getModified()));
 111   
 112  15499 return new Record(key, v, meta);
 113    } catch (BTreeNotFoundException e) {
 114  8932 if (log.isDebugEnabled()) {
 115  0 log.debug("Record '" + key + "' not found: " + e);
 116    }
 117    } catch (IOException e) {
 118  0 throw new FilerException(FaultCodes.DBE_CANNOT_READ,
 119    "Can't read record '" + key + "': " + e.getMessage(), e);
 120    }
 121  8932 return null;
 122    }
 123   
 124  13153 public Record writeRecord(Key key, Value value) throws DBException {
 125  13153 if (key == null || key.getLength() == 0) {
 126  2 throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Invalid key: null or empty");
 127    }
 128  13151 if (value == null) {
 129  1 throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Invalid value: null");
 130    }
 131   
 132  13150 checkOpened();
 133  13151 try {
 134  13151 long pos = addKey(key);
 135  13151 Page p = getPage(pos);
 136   
 137  13150 BTreeFilerPageHeader ph = (BTreeFilerPageHeader) p.getPageHeader();
 138  13151 long t = System.currentTimeMillis();
 139  13151 if (ph.getStatus() == UNUSED) {
 140  8168 ph.setCreated(t);
 141    }
 142  13151 ph.setModified(t);
 143  13151 ph.setStatus(RECORD);
 144   
 145  13151 writeValue(p, value);
 146  13151 flush();
 147   
 148  13151 HashMap meta = new HashMap(3);
 149  13151 meta.put(Record.CREATED, new Long(ph.getCreated()));
 150  13151 meta.put(Record.MODIFIED, new Long(t));
 151  13151 return new Record(key, value, meta);
 152   
 153    } catch (IOException e) {
 154    // FIXME: cleanup?
 155  0 throw new FilerException(FaultCodes.DBE_CANNOT_CREATE,
 156    "Can't write record '" + key + "': " + e.getMessage(), e);
 157    }
 158    }
 159   
 160  2963 public boolean deleteRecord(Key key) throws DBException {
 161  2963 if (key == null || key.getLength() == 0) {
 162  2 return false;
 163    }
 164   
 165  2961 checkOpened();
 166  2961 try {
 167  2961 long pos = removeValue(key);
 168  2726 Page p = getPage(pos);
 169  2726 unlinkPages(p);
 170   
 171  2726 fileHeader.decRecordCount();
 172   
 173  2726 flush();
 174  2726 return true;
 175    } catch (BTreeNotFoundException e) {
 176  235 if (log.isDebugEnabled()) {
 177  0 log.debug("Record '" + key + "' not found (" + e + ")");
 178    }
 179    } catch (IOException e) {
 180  0 throw new FilerException(FaultCodes.DBE_CANNOT_DROP,
 181    "Can't delete record '" + key + "': " + e.getMessage(), e);
 182    }
 183   
 184  235 return false;
 185    }
 186   
 187  148 public long getRecordCount() throws DBException {
 188  148 checkOpened();
 189  148 return fileHeader.getRecordCount();
 190    }
 191   
 192  350 public RecordSet getRecordSet() throws DBException {
 193  350 checkOpened();
 194  350 return new BTreeFilerRecordSet();
 195    }
 196   
 197    /**
 198    * BTreeFilerRecordSet
 199    */
 200    private class BTreeFilerRecordSet implements RecordSet, BTreeCallback {
 201    private List keys = new ArrayList();
 202    private Iterator iter;
 203   
 204  350 public BTreeFilerRecordSet() throws DBException {
 205  350 try {
 206  350 query(null, this);
 207  350 iter = keys.iterator();
 208    } catch (IOException e) {
 209  0 throw new FilerException(FaultCodes.GEN_CRITICAL_ERROR,
 210    "Error generating RecordSet", e);
 211    }
 212    }
 213   
 214  21607 public synchronized boolean indexInfo(Value value, long pointer) {
 215  21607 keys.add(new Key(value));
 216  21607 return true;
 217    }
 218   
 219  21603 public synchronized Key getNextKey() {
 220  21603 return (Key) iter.next();
 221    }
 222   
 223  4 public synchronized Record getNextRecord() throws DBException {
 224  4 return readRecord((Key) iter.next(), false);
 225    }
 226   
 227  0 public synchronized Value getNextValue() throws DBException {
 228  0 return getNextRecord().getValue();
 229    }
 230   
 231  21956 public synchronized boolean hasMoreRecords() {
 232  21956 return iter.hasNext();
 233    }
 234    }
 235   
 236    ////////////////////////////////////////////////////////////////////
 237   
 238  1295 protected FileHeader createFileHeader() {
 239  1295 return new BTreeFilerHeader();
 240    }
 241   
 242  26319 protected PageHeader createPageHeader() {
 243  26319 return new BTreeFilerPageHeader();
 244    }
 245   
 246    /**
 247    * BTreeFilerHeader
 248    */
 249    private final class BTreeFilerHeader extends BTreeFileHeader {
 250    private long totalBytes;
 251   
 252  1295 public BTreeFilerHeader() {
 253    }
 254   
 255  2352 protected synchronized void read(RandomAccessFile raf) throws IOException {
 256  2352 super.read(raf);
 257  2352 totalBytes = raf.readLong();
 258    }
 259   
 260  18090 protected synchronized void write(RandomAccessFile raf) throws IOException {
 261  18090 super.write(raf);
 262  18090 raf.writeLong(totalBytes);
 263    }
 264   
 265    /** The total number of bytes in use by the file */
 266  25136 public synchronized void setTotalBytes(long totalBytes) {
 267  25136 this.totalBytes = totalBytes;
 268  25136 setDirty();
 269    }
 270   
 271    /** The total number of bytes in use by the file */
 272  0 public synchronized long getTotalBytes() {
 273  0 return totalBytes;
 274    }
 275    }
 276   
 277    /**
 278    * BTreeFilerPageHeader
 279    */
 280    private final class BTreeFilerPageHeader extends BTreePageHeader {
 281    private long created;
 282    private long modified;
 283   
 284  26319 public BTreeFilerPageHeader() {
 285    }
 286   
 287  0 public BTreeFilerPageHeader(DataInput dis) throws IOException {
 288  0 super(dis);
 289    }
 290   
 291  26319 public synchronized void read(DataInput dis) throws IOException {
 292  26319 super.read(dis);
 293   
 294  26319 if (getStatus() == UNUSED) {
 295  8368 return;
 296    }
 297   
 298  17951 created = dis.readLong();
 299  17951 modified = dis.readLong();
 300    }
 301   
 302  27420 public synchronized void write(DataOutput dos) throws IOException {
 303  27420 super.write(dos);
 304  27420 dos.writeLong(created);
 305  27420 dos.writeLong(modified);
 306    }
 307   
 308  25136 public synchronized void setRecordLen(int recordLen) {
 309  25136 fileHeader.setTotalBytes((fileHeader.totalBytes - getRecordLen()) + recordLen);
 310  25136 super.setRecordLen(recordLen);
 311    }
 312   
 313    /** UNIX-time when this record was created */
 314  8168 public synchronized void setCreated(long created) {
 315  8168 this.created = created;
 316  8168 setDirty();
 317    }
 318   
 319    /** UNIX-time when this record was created */
 320  28650 public synchronized long getCreated() {
 321  28650 return created;
 322    }
 323   
 324    /** UNIX-time when this record was last modified */
 325  13151 public synchronized void setModified(long modified) {
 326  13151 this.modified = modified;
 327  13151 setDirty();
 328    }
 329   
 330    /** UNIX-time when this record was last modified */
 331  15499 public synchronized long getModified() {
 332  15499 return modified;
 333    }
 334    }
 335    }