All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.bwaldvogel.mongo.backend.memory.MemoryCollection Maven / Gradle / Ivy

There is a newer version: 1.46.0
Show newest version
package de.bwaldvogel.mongo.backend.memory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicLong;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.bwaldvogel.mongo.backend.AbstractMongoCollection;
import de.bwaldvogel.mongo.backend.DocumentComparator;
import de.bwaldvogel.mongo.bson.Document;
import de.bwaldvogel.mongo.exception.MongoServerException;

public class MemoryCollection extends AbstractMongoCollection {

    private static final Logger log = LoggerFactory.getLogger(MemoryCollection.class);

    private List documents = new ArrayList<>();
    private Queue emptyPositions = new LinkedList<>();
    private AtomicLong dataSize = new AtomicLong();

    public MemoryCollection(String databaseName, String collectionName, String idField) {
        super(databaseName, collectionName, idField);
    }

    @Override
    protected void updateDataSize(long sizeDelta) {
        dataSize.addAndGet(sizeDelta);
    }

    @Override
    protected long getDataSize() {
        return dataSize.get();
    }

    @Override
    protected Integer addDocumentInternal(Document document) {
        Integer position = emptyPositions.poll();
        if (position == null) {
            position = Integer.valueOf(documents.size());
        }

        if (position.intValue() == documents.size()) {
            documents.add(document);
        } else {
            documents.set(position.intValue(), document);
        }
        return position;
    }

    @Override
    protected Iterable matchDocuments(Document query, Iterable positions, Document orderBy, int numberToSkip, int numberToReturn) throws MongoServerException {

        List matchedDocuments = new ArrayList<>();

        for (Integer position : positions) {
            Document document = getDocument(position);
            if (documentMatchesQuery(document, query)) {
                matchedDocuments.add(document);
            }
        }

        sortDocumentsInMemory(matchedDocuments, orderBy);

        if (numberToSkip > 0) {
            matchedDocuments = matchedDocuments.subList(numberToSkip, matchedDocuments.size());
        }

        if (numberToReturn > 0 && matchedDocuments.size() > numberToReturn) {
            matchedDocuments = matchedDocuments.subList(0, numberToReturn);
        }

        return matchedDocuments;
    }

    @Override
    protected Iterable matchDocuments(Document query, Document orderBy, int numberToSkip,
            int numberToReturn) throws MongoServerException {
        List matchedDocuments = new ArrayList<>();

        boolean ascending = true;
        if (orderBy != null && !orderBy.keySet().isEmpty()) {
            if (orderBy.keySet().iterator().next().equals("$natural")) {
                int sortValue = ((Integer) orderBy.get("$natural")).intValue();
                if (sortValue == -1) {
                    ascending = false;
                }
            }
        }

        for (Document document : iterateAllDocuments(ascending)) {
            if (documentMatchesQuery(document, query)) {
                matchedDocuments.add(document);
            }
        }

        if (orderBy != null && !orderBy.keySet().isEmpty()) {
            if (orderBy.keySet().iterator().next().equals("$natural")) {
                // already sorted
            } else {
                Collections.sort(matchedDocuments, new DocumentComparator(orderBy));
            }
        }

        if (numberToSkip > 0) {
            if (numberToSkip < matchedDocuments.size()) {
                matchedDocuments = matchedDocuments.subList(numberToSkip, matchedDocuments.size());
            } else {
                return Collections.emptyList();
            }
        }

        if (numberToReturn > 0 && matchedDocuments.size() > numberToReturn) {
            matchedDocuments = matchedDocuments.subList(0, numberToReturn);
        }

        return matchedDocuments;
    }

    private static abstract class AbstractDocumentIterator implements Iterator {

        protected int pos;
        protected final List documents;
        protected Document current;

        protected AbstractDocumentIterator(List documents, int pos) {
            this.documents = documents;
            this.pos = pos;
        }

        protected abstract Document getNext();

        @Override
        public boolean hasNext() {
            if (current == null) {
                current = getNext();
            }
            return (current != null);
        }

        @Override
        public Document next() {
            Document document = current;
            current = getNext();
            return document;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }

    }

    private static class DocumentIterator extends AbstractDocumentIterator {

        protected DocumentIterator(List documents) {
            super(documents, 0);
        }

        @Override
        protected Document getNext() {
            while (pos < documents.size()) {
                Document document = documents.get(pos++);
                if (document != null) {
                    return document;
                }
            }
            return null;
        }

    }

    private static class ReverseDocumentIterator extends AbstractDocumentIterator {

        protected ReverseDocumentIterator(List documents) {
            super(documents, documents.size() - 1);
        }

        @Override
        protected Document getNext() {
            while (pos >= 0) {
                Document document = documents.get(pos--);
                if (document != null) {
                    return document;
                }
            }
            return null;
        }

    }

    private static class DocumentIterable implements Iterable {

        private List documents;

        public DocumentIterable(List documents) {
            this.documents = documents;
        }

        @Override
        public Iterator iterator() {
            return new DocumentIterator(documents);
        }

    }

    private static class ReverseDocumentIterable implements Iterable {

        private List documents;

        public ReverseDocumentIterable(List documents) {
            this.documents = documents;
        }

        @Override
        public Iterator iterator() {
            return new ReverseDocumentIterator(documents);
        }

    }

    private Iterable iterateAllDocuments(boolean ascending) {
        if (ascending) {
            return new DocumentIterable(documents);
        } else {
            return new ReverseDocumentIterable(documents);
        }
    }

    @Override
    public synchronized int count() {
        return documents.size() - emptyPositions.size();
    }

    @Override
    protected Integer findDocument(Document document) {
        int position = documents.indexOf(document);
        if (position < 0) {
            return null;
        }
        return Integer.valueOf(position);
    }

    @Override
    protected int getRecordCount() {
        return documents.size();
    }

    @Override
    protected int getDeletedCount() {
        return emptyPositions.size();
    }

    @Override
    protected void removeDocument(Integer position) {
        documents.set(position.intValue(), null);
        emptyPositions.add(position);
    }

    @Override
    protected Document getDocument(Integer position) {
        return documents.get(position.intValue());
    }

    @Override
    public void drop() {
        log.debug("dropping {}", this);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy