示例#1
0
  /**
   * Updates (renames) an element, attribute or pi name.
   *
   * @param pre pre value
   * @param kind node kind
   * @param name new tag, attribute or pi name
   * @param uri uri
   */
  public final void update(final int pre, final int kind, final byte[] name, final byte[] uri) {

    meta.update();

    if (kind == PI) {
      updateText(pre, trim(concat(name, SPACE, atom(pre))), kind);
    } else {
      // update/set namespace reference
      final int ouri = nspaces.uri(name, pre, this);
      final boolean ne = ouri == 0 && uri.length != 0;
      final int npre = kind == ATTR ? parent(pre, kind) : pre;
      final int nuri =
          ne
              ? nspaces.add(npre, npre, prefix(name), uri, this)
              : ouri != 0 && eq(nspaces.uri(ouri), uri) ? ouri : 0;

      // write namespace uri reference
      table.write1(pre, kind == ELEM ? 3 : 11, nuri);
      // write name reference
      table.write2(
          pre,
          1,
          (nsFlag(pre) ? 1 << 15 : 0)
              | (kind == ELEM ? tagindex : atnindex).index(name, null, false));
      // write namespace flag
      table.write2(npre, 1, (ne || nsFlag(npre) ? 1 << 15 : 0) | name(npre));
    }
  }
示例#2
0
  @Override
  public DiskData build() throws IOException {
    meta.assign(parser);
    meta.dirty = true;

    // calculate optimized output buffer sizes to reduce disk fragmentation
    final Runtime rt = Runtime.getRuntime();
    final long max = Math.min(1 << 22, rt.maxMemory() - rt.freeMemory() >> 2);
    int bs = (int) Math.min(meta.filesize, max);
    bs = Math.max(IO.BLOCKSIZE, bs - bs % IO.BLOCKSIZE);

    // drop old database (if available) and create new one
    DropDB.drop(dbname, sopts);
    sopts.dbpath(dbname).md();

    elemNames = new Names(meta);
    attrNames = new Names(meta);
    try {
      tout = new DataOutput(new TableOutput(meta, DATATBL));
      xout = new DataOutput(meta.dbfile(DATATXT), bs);
      vout = new DataOutput(meta.dbfile(DATAATV), bs);
      sout = new DataOutput(meta.dbfile(DATATMP), bs);

      final Performance perf = Prop.debug ? new Performance() : null;
      Util.debug(tit() + DOTS);
      parse();
      if (Prop.debug) Util.errln(" " + perf + " (" + Performance.getMemory() + ')');

    } catch (final IOException ex) {
      try {
        close();
      } catch (final IOException ignored) {
      }
      throw ex;
    }
    close();

    // copy temporary values into database table
    try (final DataInput in = new DataInput(meta.dbfile(DATATMP))) {
      final TableAccess ta = new TableDiskAccess(meta, true);
      for (; spos < ssize; ++spos) ta.write4(in.readNum(), 8, in.readNum());
      ta.close();
    }
    meta.dbfile(DATATMP).delete();

    // return database instance
    return new DiskData(meta, elemNames, attrNames, path, ns);
  }
示例#3
0
 /**
  * Returns the distance of the specified node.
  *
  * @param pre pre value
  * @param kind node kind
  * @return distance
  */
 public int dist(final int pre, final int kind) {
   switch (kind) {
     case ELEM:
       return table.read4(pre, 4);
     case TEXT:
     case COMM:
     case PI:
       return table.read4(pre, 8);
     case ATTR:
       int d = table.read1(pre, 0) >> 3 & IO.MAXATTS;
       // skip additional attributes, if value is larger than maximum range
       if (d >= IO.MAXATTS) while (d < pre && kind(pre - d) == ATTR) d++;
       return d;
     default:
       return pre + 1;
   }
 }
示例#4
0
  /**
   * Deletes a node and its descendants.
   *
   * @param pre pre value of the node to delete
   */
  public final void delete(final int pre) {
    meta.update();

    // size of the subtree to delete
    int k = kind(pre);
    final int s = size(pre, k);
    resources.delete(pre, s);

    if (meta.updindex) {
      // delete child records from indexes
      indexDelete(pre, s);
    }

    /// explicitly delete text or attribute value
    if (k != DOC && k != ELEM) delete(pre, k != ATTR);

    // reduce size of ancestors
    int par = pre;
    // check if we are an attribute (different size counters)
    if (k == ATTR) {
      par = parent(par, ATTR);
      attSize(par, ELEM, attSize(par, ELEM) - 1);
      size(par, ELEM, size(par, ELEM) - 1);
      k = kind(par);
    }

    // reduce size of ancestors
    while (par > 0 && k != DOC) {
      par = parent(par, k);
      k = kind(par);
      size(par, k, size(par, k) - s);
    }

    // preserve empty root node
    if (kind(pre) == DOC) --meta.ndocs;

    if (meta.updindex) {
      // delete node and descendants from ID -> PRE map:
      idmap.delete(pre, id(pre), -s);
    }

    // delete node from table structure and reduce document size
    table.delete(pre, s);

    if (!cache) updateDist(pre, -s);

    // propagate PRE value shifts to namespaces
    nspaces.delete(pre, s, this);
  }
示例#5
0
 /**
  * Sets the attribute size.
  *
  * @param pre pre value
  * @param kind node kind
  * @param value value
  */
 private void attSize(final int pre, final int kind, final int value) {
   if (kind == ELEM) table.write1(pre, 0, value << 3 | ELEM);
 }
示例#6
0
 /**
  * Sets the distance.
  *
  * @param pre pre value
  * @param kind node kind
  * @param value value
  */
 public void dist(final int pre, final int kind, final int value) {
   if (kind == ATTR) table.write1(pre, 0, value << 3 | ATTR);
   else if (kind != DOC) table.write4(pre, kind == ELEM ? 4 : 8, value);
 }
示例#7
0
 /**
  * Sets the disk offset of a text/attribute value.
  *
  * @param pre pre value
  * @param off offset
  */
 final void textOff(final int pre, final long off) {
   table.write5(pre, 3, off);
 }
示例#8
0
 /**
  * Sets the size value.
  *
  * @param pre pre reference
  * @param kind node kind
  * @param value value to be stored
  */
 public final void size(final int pre, final int kind, final int value) {
   if (kind == ELEM || kind == DOC) table.write4(pre, 8, value);
 }
示例#9
0
  /**
   * Inserts a data instance at the specified pre value. Note that the specified data instance must
   * differ from this instance.
   *
   * @param ipre value at which to insert new data
   * @param ipar parent pre value of node
   * @param clip data clip
   */
  public final void insert(final int ipre, final int ipar, final DataClip clip) {
    meta.update();

    // update value and document indexes
    if (meta.updindex) indexBegin();
    resources.insert(ipre, clip);

    final int dsize = clip.size();
    final int buf = Math.min(dsize, IO.BLOCKSIZE >> IO.NODEPOWER);
    // resize buffer to cache more entries
    buffer(buf);

    // find all namespaces in scope to avoid duplicate declarations
    final TokenMap nsScope = nspaces.scope(ipar, this);

    // loop through all entries
    final IntList preStack = new IntList();
    final NSNode nsRoot = nspaces.current();
    final HashSet<NSNode> newNodes = new HashSet<NSNode>();
    final IntList flagPres = new IntList();

    // indicates if database only contains a dummy node
    final Data data = clip.data;
    int c = 0;
    for (int dpre = clip.start; dpre < clip.end; ++dpre, ++c) {
      if (c != 0 && c % buf == 0) insert(ipre + c - buf);

      final int pre = ipre + c;
      final int dkind = data.kind(dpre);
      final int dpar = data.parent(dpre, dkind);
      // ipar < 0 if document nodes on top level are added
      final int dis = dpar >= 0 ? dpre - dpar : ipar >= 0 ? pre - ipar : 0;
      final int par = dis == 0 ? -1 : pre - dis;

      if (c == 0) nspaces.root(par, this);

      while (!preStack.isEmpty() && preStack.peek() > par) nspaces.close(preStack.pop());

      switch (dkind) {
        case DOC:
          // add document
          nspaces.prepare();
          final int s = data.size(dpre, dkind);
          doc(pre, s, data.text(dpre, true));
          meta.ndocs++;
          preStack.push(pre);
          break;
        case ELEM:
          // add element
          nspaces.prepare();
          boolean ne = false;
          if (data.nsFlag(dpre)) {
            final Atts at = data.ns(dpre);
            for (int a = 0; a < at.size(); ++a) {
              // see if prefix has been declared/ is part of current ns scope
              final byte[] old = nsScope.get(at.name(a));
              if (old == null || !eq(old, at.value(a))) {
                // we have to keep track of all new NSNodes that are added
                // to the Namespace structure, as their pre values must not
                // be updated. I.e. if an NSNode N with pre value 3 existed
                // prior to inserting and two new nodes are inserted at
                // location pre == 3 we have to make sure N and only N gets
                // updated.
                newNodes.add(nspaces.add(at.name(a), at.value(a), pre));
                ne = true;
              }
            }
          }
          byte[] nm = data.name(dpre, dkind);
          elem(
              dis,
              tagindex.index(nm, null, false),
              data.attSize(dpre, dkind),
              data.size(dpre, dkind),
              nspaces.uri(nm, true),
              ne);
          preStack.push(pre);
          break;
        case TEXT:
        case COMM:
        case PI:
          // add text
          text(pre, dis, data.text(dpre, true), dkind);
          break;
        case ATTR:
          // add attribute
          nm = data.name(dpre, dkind);
          // check if prefix already in nsScope or not
          final byte[] attPref = prefix(nm);
          // check if prefix of attribute has already been declared, otherwise
          // add declaration to parent node
          if (data.nsFlag(dpre) && nsScope.get(attPref) == null) {
            nspaces.add(
                par,
                preStack.isEmpty() ? -1 : preStack.peek(),
                attPref,
                data.nspaces.uri(data.uri(dpre, dkind)),
                this);
            // save pre value to set ns flag later for this node. can't be done
            // here as direct table access would interfere with the buffer
            flagPres.add(par);
          }
          attr(
              pre,
              dis,
              atnindex.index(nm, null, false),
              data.text(dpre, false),
              nspaces.uri(nm, false),
              false);
          break;
      }
    }
    // finalize and update namespace structure
    while (!preStack.isEmpty()) nspaces.close(preStack.pop());
    nspaces.root(nsRoot);

    if (bp != 0) insert(ipre + c - 1 - (c - 1) % buf);
    // reset buffer to old size
    buffer(1);

    // set ns flags
    for (int f = 0; f < flagPres.size(); f++) {
      final int fl = flagPres.get(f);
      table.write2(fl, 1, name(fl) | 1 << 15);
    }

    // increase size of ancestors
    int p = ipar;
    while (p >= 0) {
      final int k = kind(p);
      size(p, k, size(p, k) + dsize);
      p = parent(p, k);
    }

    if (meta.updindex) {
      // add the entries to the ID -> PRE mapping:
      idmap.insert(ipre, id(ipre), dsize);
      indexEnd();
    }

    if (!cache) updateDist(ipre + dsize, dsize);

    // propagate PRE value shifts to namespaces
    if (ipar != -1) nspaces.insert(ipre, dsize, newNodes);
  }
示例#10
0
 /**
  * Returns the disk offset of a text (text, comment, pi) or attribute value.
  *
  * @param pre pre value
  * @return disk offset
  */
 final long textOff(final int pre) {
   return table.read5(pre, 3);
 }
示例#11
0
 /**
  * Returns a unique node id.
  *
  * @param pre pre value
  * @return node id
  */
 public final int id(final int pre) {
   return table.read4(pre, 12);
 }
示例#12
0
 /**
  * Returns a reference to the namespace of the addressed element or attribute.
  *
  * @param pre pre value
  * @param kind node kind
  * @return namespace URI
  */
 public final int uri(final int pre, final int kind) {
   return kind == ELEM || kind == ATTR ? table.read1(pre, kind == ELEM ? 3 : 11) & 0xFF : 0;
 }
示例#13
0
 /**
  * Returns the namespace flag of the addressed element.
  *
  * @param pre pre value
  * @return namespace flag
  */
 public final boolean nsFlag(final int pre) {
   return (table.read1(pre, 1) & 0x80) != 0;
 }
示例#14
0
 /**
  * Returns a reference to the tag or attribute name id.
  *
  * @param pre pre value
  * @return token reference
  */
 public final int name(final int pre) {
   return table.read2(pre, 1) & 0x7FFF;
 }
示例#15
0
 /**
  * Returns a number of attributes.
  *
  * @param pre pre value
  * @param kind node kind
  * @return number of attributes
  */
 public final int attSize(final int pre, final int kind) {
   int s = kind == ELEM ? table.read1(pre, 0) >> 3 & IO.MAXATTS : 1;
   // skip additional attributes, if value is larger than maximum range
   if (s >= IO.MAXATTS) while (s < meta.size - pre && kind(pre + s) == ATTR) s++;
   return s;
 }
示例#16
0
 /**
  * Returns a size value (number of descendant table entries).
  *
  * @param pre pre value
  * @param kind node kind
  * @return size value
  */
 public final int size(final int pre, final int kind) {
   return kind == ELEM || kind == DOC ? table.read4(pre, 8) : 1;
 }
示例#17
0
 /**
  * Sets the namespace flag. Should be only called for element nodes.
  *
  * @param pre pre value
  * @param ne namespace flag
  */
 public final void nsFlag(final int pre, final boolean ne) {
   table.write1(pre, 1, table.read1(pre, 1) & 0x7F | (ne ? 0x80 : 0));
 }
示例#18
0
  /**
   * Replaces parts of the database with the specified data instance.
   *
   * @param rpre pre value to be replaced
   * @param clip data clip
   */
  public final void replace(final int rpre, final DataClip clip) {
    meta.update();

    final int dsize = clip.size();
    final Data data = clip.data;

    final int rkind = kind(rpre);
    final int rsize = size(rpre, rkind);
    final int rpar = parent(rpre, rkind);
    final int diff = dsize - rsize;
    buffer(dsize);
    resources.replace(rpre, rsize, clip);

    if (meta.updindex) {
      // update index
      indexDelete(rpre, rsize);
      indexBegin();
    }

    for (int dpre = clip.start; dpre < clip.end; ++dpre) {
      final int dkind = data.kind(dpre);
      final int dpar = data.parent(dpre, dkind);
      final int pre = rpre + dpre - clip.start;
      final int dis = dpar >= 0 ? dpre - dpar : pre - rpar;

      switch (dkind) {
        case DOC:
          // add document
          doc(pre, data.size(dpre, dkind), data.text(dpre, true));
          meta.ndocs++;
          break;
        case ELEM:
          // add element
          byte[] nm = data.name(dpre, dkind);
          elem(
              dis,
              tagindex.index(nm, null, false),
              data.attSize(dpre, dkind),
              data.size(dpre, dkind),
              nspaces.uri(nm, true),
              false);
          break;
        case TEXT:
        case COMM:
        case PI:
          // add text
          text(pre, dis, data.text(dpre, true), dkind);
          break;
        case ATTR:
          // add attribute
          nm = data.name(dpre, dkind);
          attr(
              pre,
              dis,
              atnindex.index(nm, null, false),
              data.text(dpre, false),
              nspaces.uri(nm, false),
              false);
          break;
      }
    }

    if (meta.updindex) {
      indexEnd();
      // update ID -> PRE map:
      idmap.delete(rpre, id(rpre), -rsize);
      idmap.insert(rpre, meta.lastid - dsize + 1, dsize);
    }

    // update table:
    table.replace(rpre, buffer(), rsize);
    buffer(1);

    // no distance/size update if the two subtrees are of equal size
    if (diff == 0) return;

    // increase/decrease size of ancestors, adjust distances of siblings
    int p = rpar;
    while (p >= 0) {
      final int k = kind(p);
      size(p, k, size(p, k) + diff);
      p = parent(p, k);
    }

    if (!cache) updateDist(rpre + dsize, diff);

    // adjust attribute size of parent if attributes inserted. attribute size
    // of parent cannot be reduced via a replace expression.
    int dpre = clip.start;
    if (data.kind(dpre) == ATTR) {
      int d = 0;
      while (dpre < clip.end && data.kind(dpre++) == ATTR) d++;
      if (d > 1) attSize(rpar, kind(rpar), d + 1);
    }
  }
示例#19
0
 /**
  * Inserts the internal buffer to the storage without updating the table structure.
  *
  * @param pre insert position
  */
 public final void insert(final int pre) {
   table.insert(pre, buffer());
 }
示例#20
0
 /**
  * Returns the node kind, which may be {@link #DOC}, {@link #ELEM}, {@link #TEXT}, {@link #ATTR},
  * {@link #COMM} or {@link #PI}.
  *
  * @param pre pre value
  * @return node kind
  */
 public final int kind(final int pre) {
   return table.read1(pre, 0) & 0x07;
 }