Package org.apache.jackrabbit.mk.simple

Source Code of org.apache.jackrabbit.mk.simple.NodeListSmall

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.mk.simple;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Iterator;
import org.apache.jackrabbit.mk.json.JsopBuilder;
import org.apache.jackrabbit.mk.json.JsopWriter;
import org.apache.jackrabbit.mk.simple.NodeImpl.ChildVisitor;
import org.apache.jackrabbit.oak.commons.ArrayUtils;
import org.apache.jackrabbit.mk.util.ExceptionFactory;
import org.apache.jackrabbit.mk.util.IOUtils;
import org.apache.jackrabbit.mk.util.StringCache;

/**
* A list of child nodes that fits in memory.
*/
public class NodeListSmall implements NodeList {

    /**
     * The number of (direct) child nodes.
     */
    int size;

    /**
     * The child node names, in order they were added.
     */
    String[] names;

    /**
     * The child node ids.
     */
    private NodeId[] children;

    /**
     * The sort index.
     */
    private int[] sort;

    /**
     * The index of the last child node name lookup (to speed up name lookups).
     */
    private int lastNameIndexCache;

    NodeListSmall() {
        this(ArrayUtils.EMPTY_STRING_ARRAY, NodeId.EMPTY_ARRAY, ArrayUtils.EMPTY_INTEGER_ARRAY, 0);
    }

    private NodeListSmall(String[] names, NodeId[] children, int[] sort, int size) {
        this.names = names;
        this.children = children;
        this.sort = sort;
        this.size = size;
    }

    @Override
    public long size() {
        return size;
    }

    @Override
    public boolean containsKey(String name) {
        return find(name) >= 0;
    }

    private int find(String name) {
        // copy, to avoid concurrency issues
        int last = lastNameIndexCache;
        if (last < size && names[sort[last]].equals(name)) {
            return last;
        }
        int min = 0, max = size - 1;
        while (min <= max) {
            int test = (min + max) >>> 1;
            int compare = names[sort[test]].compareTo(name);
            if (compare == 0) {
                lastNameIndexCache = test;
                return test;
            }
            if (compare > 0) {
                max = test - 1;
            } else if (compare < 0) {
                min = test + 1;
            }
        }
        // not found: return negative insertion point
        return -(min + 1);
    }

    @Override
    public NodeId get(String name) {
        int index = find(name);
        if (index < 0) {
            return null;
        }
        return children[sort[index]];
    }

    @Override
    public void add(String name, NodeId x) {
        int index = find(name);
        if (index >= 0) {
            throw ExceptionFactory.get("Node already exists: " + name);
        }
        index = -index - 1;
        name = StringCache.cache(name);
        names = ArrayUtils.arrayInsert(names, size, name);
        children = ArrayUtils.arrayInsert(children, size, x);
        sort = ArrayUtils.arrayInsert(sort, index, size);
        size++;
    }

    @Override
    public void replace(String name, NodeId x) {
        int index = find(name);
        if (index < 0) {
            throw ExceptionFactory.get("Node not found: " + name);
        }
        children = ArrayUtils.arrayReplace(children, sort[index], x);
    }

    @Override
    public String getName(long pos) {
        return pos >= names.length ? null : names[(int) pos];
    }

    @Override
    public Iterator<String> getNames(final long offset, final int maxCount) {
        return  new Iterator<String>() {
            int pos = (int) offset;
            int remaining = maxCount;
            @Override
            public boolean hasNext() {
                return pos < size && remaining > 0;
            }
            @Override
            public String next() {
                remaining--;
                return names[pos++];
            }
            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }

    @Override
    public NodeId remove(String name) {
        int index = find(name);
        if (index < 0) {
            throw ExceptionFactory.get("Node not found: " + name);
        }
        int s = sort[index];
        NodeId result = children[s];
        names = ArrayUtils.arrayRemove(names, s);
        children = ArrayUtils.arrayRemove(children, s);
        sort = ArrayUtils.arrayRemove(sort, index);
        if (s != size - 1) {
            for (int i = 0; i < sort.length; i++) {
                if (sort[i] >= s) {
                    sort[i]--;
                }
            }
        }
        size--;
        return result;
    }

    @Override
    public String toString() {
        JsopWriter json = new JsopBuilder();
        json.object();
        for (int i = 0; i < size; i++) {
            json.key(names[i]).value(children[i].toString());
        }
        json.endObject();
        return json.toString();
    }

    @Override
    public NodeList createClone(NodeMap map, long revId) {
        NodeList result = new NodeListSmall(names, children, sort, size);
        if (size > map.getMaxMemoryChildren()) {
            return new NodeListTrie(map, result, size, revId);
        }
        return result;
    }

    @Override
    public void visit(ChildVisitor v) {
        for (NodeId c : children) {
            v.accept(c);
        }
    }

    @Override
    public void append(JsopWriter json, NodeMap map) {
        for (int i = 0; i < size; i++) {
            json.key(names[i]);
            NodeId x = children[i];
            NodeId y = map.getId(x);
            if (x != y) {
                children[i] = y;
            }
            json.encodedValue(map.formatId(y));
        }
    }

    @Override
    public int getMemory() {
        int memory = 100;
        for (int i = 0; i < names.length; i++) {
            memory += names[i].length() * 2 + 8;
        }
        return memory;
    }

    @Override
    public int hashCode() {
        if (size == 0) {
            return 0;
        }
        return Arrays.hashCode(names) ^
                Arrays.hashCode(children) ^
                Arrays.hashCode(sort);
    }

    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        }
        if (other instanceof NodeListSmall) {
            NodeListSmall o = (NodeListSmall) other;
            if (size == o.size) {
                if (size == 0) {
                    return true;
                }
                return Arrays.equals(sort, o.sort) &&
                        Arrays.equals(children, o.children) &&
                        Arrays.equals(names, o.names);
            }
        }
        return false;
    }

    @Override
    public void updateHash(NodeMap map, OutputStream out) throws IOException {
        if (children != null) {
            try {
                for (int s : sort) {
                    String n = names[s];
                    IOUtils.writeString(out, n);
                    NodeId c = children[s];
                    byte[] hash = c.getHash();
                    if (hash == null) {
                        hash = map.getNode(c.getLong()).getHash();
                    }
                    out.write(hash);
                }
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        }
    }

}
TOP

Related Classes of org.apache.jackrabbit.mk.simple.NodeListSmall

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.