Archived
0

implement berkeley bd

This commit is contained in:
iMoHax
2015-01-14 17:13:59 +03:00
parent 0e4dc496e3
commit 038e920883
15 changed files with 936 additions and 34 deletions

View File

@@ -1,31 +1,94 @@
package ru.trader.store.berkeley;
import ru.trader.core.AbstractItemStat;
import ru.trader.core.Item;
import ru.trader.core.OFFER_TYPE;
import ru.trader.core.Offer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.trader.core.*;
import java.util.Collections;
import java.util.NavigableSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.DoubleAdder;
//TODO: implement
public class BDBItemStat extends AbstractItemStat {
private final static Logger LOG = LoggerFactory.getLogger(BDBItemStat.class);
private final ItemProxy item;
private final OFFER_TYPE type;
private final BDBStore store;
private NavigableSet<Offer> offers;
private volatile double sum;
private volatile double avg;
private AtomicLong count;
public BDBItemStat(ItemProxy item, OFFER_TYPE type, BDBStore store) {
this.item = item;
this.type = type;
this.store = store;
offers = new TreeSet<>(store.getOfferAccessor().getAllByItem(item.getId(), type));
this.sum = 0;
this.avg = Double.NaN;
this.count = new AtomicLong(0);
init();
}
void init(){
sum = 0;
count.set(0);
offers.forEach(o -> {
sum += o.getPrice();
count.incrementAndGet();
});
avg = sum / count.get();
}
synchronized void put(Offer offer){
LOG.trace("Put offer {} to item stat {}", offer, this);
assert offer.hasType(type) && offer.hasItem(item);
double price = offer.getPrice();
sum += price;
avg = sum / count.incrementAndGet();
if (offers != null){
offers.add(offer);
}
LOG.trace("After this = {}", this);
}
synchronized void remove(Offer offer){
LOG.trace("Remove offer {} from item stat {}", offer, this);
assert offer.hasType(type) && offer.hasItem(item);
double price = offer.getPrice();
sum -= price;
if (count.decrementAndGet() > 0){
avg = sum / count.get();
} else {
sum = 0; avg = Double.NaN;
}
if (offers != null){
offers.remove(offer);
}
LOG.trace("After this = {}", this);
}
@Override
protected synchronized void updatePrice(AbstractOffer offer, double price) {
LOG.trace("Update offer {} from item stat {}", offer, this);
assert offer.hasType(type) && offer.hasItem(item);
double oldPrice = offer.getPrice();
if (offers != null){
offers.remove(offer);
}
super.updatePrice(offer, price);
if (offers != null){
offers.add(offer);
}
sum += price - oldPrice;
avg = sum / offers.size();
LOG.trace("After update this = {}", this);
}
@Override
public OFFER_TYPE getType() {
@@ -39,31 +102,69 @@ public class BDBItemStat extends AbstractItemStat {
@Override
public Offer getMin() {
return null;
if (count.get() == 0) return getFake();
return offers.first();
}
@Override
public double getAvg() {
return 0;
return avg;
}
@Override
public Offer getMax() {
return null;
if (offers.isEmpty()) return getFake();
return offers.last();
}
@Override
public Offer getBest() {
return null;
if (offers.isEmpty()) return getFake();
return type.getOrder() > 0 ? offers.first() : offers.last();
}
@Override
public NavigableSet<Offer> getOffers() {
return null;
return Collections.unmodifiableNavigableSet(offers);
}
@Override
public boolean isEmpty() {
return false;
return count.get() == 0;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BDBItemStat)) return false;
BDBItemStat itemStat = (BDBItemStat) o;
return type == itemStat.type && item.equals(itemStat.item);
}
@Override
public int hashCode() {
int result = item.hashCode();
result = 31 * result + type.hashCode();
return result;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append(getItem());
sb.append(", ").append(getType());
if (BDBItemStat.LOG.isTraceEnabled()){
sb.append(", count=").append(offers.size());
sb.append(", sum=").append(sum);
}
sb.append(", avg=").append(getAvg());
sb.append(", best=").append(getBest());
sb.append(", min=").append(getMin());
sb.append(", max=").append(getMax());
sb.append("}");
return sb.toString();
}
}

View File

@@ -1,5 +1,7 @@
package ru.trader.store.berkeley;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.trader.core.*;
import ru.trader.store.berkeley.entities.BDBGroup;
import ru.trader.store.berkeley.entities.BDBItem;
@@ -8,12 +10,17 @@ import ru.trader.store.berkeley.entities.BDBPlace;
import java.util.*;
public class BDBMarket extends AbstractMarket {
private final static Logger LOG = LoggerFactory.getLogger(BDBMarket.class);
private final BDBStore store;
//caching
private final Map<Item,BDBItemStat> sellItems = new HashMap<>();
private final Map<Item,BDBItemStat> buyItems = new HashMap<>();
public BDBMarket(BDBStore store) {
this.store = store;
store.setMarket(this);
}
private Map<Item,BDBItemStat> getItemCache(OFFER_TYPE offerType){
switch (offerType) {
@@ -30,8 +37,9 @@ public class BDBMarket extends AbstractMarket {
if (entry == null){
entry = new BDBItemStat((ItemProxy) item, offer.getType(), store);
cache.put(item, entry);
} else {
entry.put(offer);
}
entry.put(offer);
}
private void remove(Map<Item, BDBItemStat> cache, Offer offer){
@@ -44,10 +52,6 @@ public class BDBMarket extends AbstractMarket {
}
}
public BDBMarket(BDBStore store) {
this.store = store;
}
@Override
protected Place createPlace(String name, double x, double y, double z) {
return new PlaceProxy(new BDBPlace(name, x, y, z), store);
@@ -70,6 +74,9 @@ public class BDBMarket extends AbstractMarket {
@Override
protected void removePlace(Place place) {
for (Vendor vendor : place.get()) {
onRemove(vendor);
}
store.getPlaceAccessor().delete(((PlaceProxy) place).getEntity());
}
@@ -91,6 +98,8 @@ public class BDBMarket extends AbstractMarket {
@Override
protected void removeItem(Item item) {
store.getItemAccessor().delete(((ItemProxy) item).getEntity());
sellItems.remove(item);
buyItems.remove(item);
}
@Override
@@ -110,8 +119,50 @@ public class BDBMarket extends AbstractMarket {
@Override
public ItemStat getStat(OFFER_TYPE type, Item item) {
//TODO: добавить
return null;
ItemStat entry = getItemCache(type).get(item);
if (entry == null){
entry = new BDBItemStat((ItemProxy) item, type, store);
getItemCache(type).put(item, (BDBItemStat) entry);
}
return entry;
}
@Override
protected void onAdd(Vendor vendor) {
LOG.trace("Cached on add vendor {}", vendor);
Collection<Offer> offers = vendor.getAllSellOffers();
for (Offer offer : offers) {
put(sellItems, offer);
}
offers = vendor.getAllBuyOffers();
for (Offer offer : offers) {
put(buyItems, offer);
}
}
@Override
protected void onRemove(Vendor vendor) {
LOG.trace("Remove cache of vendor {}", vendor);
Collection<Offer> offers = vendor.getAllSellOffers();
for (Offer offer : offers) {
remove(sellItems, offer);
}
offers = vendor.getAllBuyOffers();
for (Offer offer : offers) {
remove(buyItems, offer);
}
}
@Override
protected void onAdd(Offer offer) {
LOG.trace("Cached on add offer {}", offer);
put(getItemCache(offer.getType()), offer);
}
@Override
protected void onRemove(Offer offer) {
LOG.trace("Remove cache of offer {}", offer);
remove(getItemCache(offer.getType()), offer);
}
}

View File

@@ -23,6 +23,7 @@ public class BDBStore {
private final ItemDA<Item> iDA;
private final GroupDA<Group> gDA;
private final PlaceDA<Place> pDA;
private BDBMarket market;
public BDBStore(String path){
EnvironmentConfig envConfig = new EnvironmentConfig();
@@ -39,7 +40,7 @@ public class BDBStore {
oDA = new OfferDA<>(store, o -> new OfferProxy(o, this));
iDA = new ItemDA<>(store, i -> new ItemProxy(i, this));
gDA = new GroupDA<>(store, g -> g);
pDA = new PlaceDA<>(store, p -> new PlaceProxy(p, this));
pDA = new PlaceDA<>(store, p -> new PlaceProxy(p, null, this));
} catch (DatabaseException e){
LOG.error("Error on open DB, path {}", path);
@@ -48,6 +49,12 @@ public class BDBStore {
}
}
void setMarket(BDBMarket market) {
assert this.market == null;
this.market = market;
pDA.setConvertFunc(p -> new PlaceProxy(p, market, this));
}
public VendorDA<Vendor> getVendorAccessor() {
return vDA;
}

View File

@@ -7,11 +7,10 @@ import ru.trader.store.berkeley.entities.BDBItem;
public class ItemProxy extends AbstractItem {
private final BDBItem item;
private final BDBStore store;
private final Group group;
private Group group;
public ItemProxy(BDBItem item, BDBStore store) {
this.item = item;
this.group = store.getGroupAccessor().get(item.getGroupId());
this.store = store;
}
@@ -36,7 +35,26 @@ public class ItemProxy extends AbstractItem {
@Override
public Group getGroup() {
if (group == null){
group = store.getGroupAccessor().get(item.getGroupId());
}
return group;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ItemProxy)) return false;
ItemProxy itemProxy = (ItemProxy) o;
if (!item.equals(itemProxy.item)) return false;
return true;
}
@Override
public int hashCode() {
return item.hashCode();
}
}

View File

@@ -5,13 +5,12 @@ import ru.trader.store.berkeley.entities.BDBOffer;
public class OfferProxy extends AbstractOffer {
private final BDBOffer offer;
private final Item item;
private Item item;
private BDBStore store;
private Vendor vendor;
public OfferProxy(BDBOffer offer, BDBStore store) {
this.offer = offer;
this.item = store.getItemAccessor().get(offer.getItemId());
this.store = store;
}
@@ -43,6 +42,9 @@ public class OfferProxy extends AbstractOffer {
@Override
public Item getItem() {
if (item == null){
item = store.getItemAccessor().get(offer.getItemId());
}
return item;
}
@@ -69,4 +71,20 @@ public class OfferProxy extends AbstractOffer {
return offer.getCount();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof OfferProxy)) return false;
OfferProxy that = (OfferProxy) o;
if (!offer.equals(that.offer)) return false;
return true;
}
@Override
public int hashCode() {
return offer.hashCode();
}
}

View File

@@ -16,6 +16,11 @@ public class PlaceProxy extends AbstractPlace {
this.store = store;
}
public PlaceProxy(BDBPlace place, BDBMarket market, BDBStore store) {
this(place, store);
setMarket(market);
}
protected long getId(){
return place.getId();
}
@@ -76,4 +81,20 @@ public class PlaceProxy extends AbstractPlace {
return store.getVendorAccessor().getAllByPlace(place.getId());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PlaceProxy)) return false;
PlaceProxy that = (PlaceProxy) o;
if (!place.equals(that.place)) return false;
return true;
}
@Override
public int hashCode() {
return place.hashCode();
}
}

View File

@@ -114,4 +114,21 @@ public class VendorProxy extends AbstractVendor {
public boolean has(OFFER_TYPE type, Item item) {
return store.getOfferAccessor().has(vendor.getId(), type, ((ItemProxy)item).getId());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof VendorProxy)) return false;
VendorProxy that = (VendorProxy) o;
if (!vendor.equals(that.vendor)) return false;
return true;
}
@Override
public int hashCode() {
return vendor.hashCode();
}
}

View File

@@ -6,6 +6,7 @@ import ru.trader.store.berkeley.entities.BDBOffer;
import java.util.Collection;
import java.util.LinkedList;
import java.util.TreeSet;
import java.util.function.Function;
public class OfferDA<T> {
@@ -78,6 +79,20 @@ public class OfferDA<T> {
return res;
}
public Collection<T> getAllByItem(long itemId, OFFER_TYPE type){
EntityJoin<Long,BDBOffer> join = new EntityJoin<>(indexById);
join.addCondition(indexByItemId, itemId);
join.addCondition(indexByType, type);
Collection<T> res = new LinkedList<>();
try (ForwardCursor<BDBOffer> cursor = join.entities())
{
for(BDBOffer entity : cursor){
res.add(convertFunc.apply(entity));
}
}
return res;
}
public BDBOffer put(BDBOffer offer){
return indexById.put(offer);

View File

@@ -13,7 +13,7 @@ import java.util.function.Function;
public class PlaceDA<T> {
private final PrimaryIndex<Long, BDBPlace> indexById;
private final SecondaryIndex<Double, Long, BDBPlace> indexByDistance;
private final Function<BDBPlace,T> convertFunc;
private Function<BDBPlace,T> convertFunc;
public PlaceDA(EntityStore store, Function<BDBPlace, T> convertFunc) {
this.convertFunc = convertFunc;
@@ -21,6 +21,10 @@ public class PlaceDA<T> {
this.indexByDistance = store.getSecondaryIndex(indexById, Double.class, "distance");
}
public void setConvertFunc(Function<BDBPlace, T> convertFunc) {
this.convertFunc = convertFunc;
}
public T get(long id){
return DAUtils.get(indexById, id, convertFunc);
}

View File

@@ -31,4 +31,24 @@ public class BDBGroup implements Group {
public GROUP_TYPE getType() {
return type;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BDBGroup)) return false;
BDBGroup bdbGroup = (BDBGroup) o;
if (!name.equals(bdbGroup.name)) return false;
if (type != bdbGroup.type) return false;
return true;
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + type.hashCode();
return result;
}
}

View File

@@ -38,4 +38,22 @@ public class BDBItem {
return groupId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BDBItem)) return false;
BDBItem bdbItem = (BDBItem) o;
if (id != bdbItem.id) return false;
if (!groupId.equals(bdbItem.groupId)) return false;
if (!name.equals(bdbItem.name)) return false;
return true;
}
@Override
public int hashCode() {
return (int) (id ^ (id >>> 32));
}
}

View File

@@ -10,21 +10,22 @@ public class BDBOffer {
private long id;
@SecondaryKey(relate = Relationship.MANY_TO_ONE,
relatedEntity = BDBItem.class,
onRelatedEntityDelete = DeleteAction.NULLIFY)
relatedEntity = BDBItem.class, onRelatedEntityDelete = DeleteAction.CASCADE)
private long itemId;
@SecondaryKey(relate = Relationship.MANY_TO_ONE,
relatedEntity = BDBVendor.class,
onRelatedEntityDelete = DeleteAction.NULLIFY)
relatedEntity = BDBVendor.class, onRelatedEntityDelete = DeleteAction.CASCADE)
private long vendorId;
@SecondaryKey(relate = Relationship.ONE_TO_ONE)
@SecondaryKey(relate = Relationship.MANY_TO_ONE)
private OFFER_TYPE type;
private double price;
private long count;
private BDBOffer() {
}
public BDBOffer(OFFER_TYPE type, long itemId, double price, long count, long vendorId) {
this.type = type;
this.itemId = itemId;
@@ -69,4 +70,24 @@ public class BDBOffer {
this.vendorId = vendorId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BDBOffer)) return false;
BDBOffer bdbOffer = (BDBOffer) o;
if (count != bdbOffer.count) return false;
if (id != bdbOffer.id) return false;
if (itemId != bdbOffer.itemId) return false;
if (Double.compare(bdbOffer.price, price) != 0) return false;
if (type != bdbOffer.type) return false;
return true;
}
@Override
public int hashCode() {
return (int) (id ^ (id >>> 32));
}
}

View File

@@ -59,4 +59,25 @@ public class BDBPlace {
this.distance = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BDBPlace)) return false;
BDBPlace bdbPlace = (BDBPlace) o;
if (id != bdbPlace.id) return false;
if (Double.compare(bdbPlace.x, x) != 0) return false;
if (Double.compare(bdbPlace.y, y) != 0) return false;
if (Double.compare(bdbPlace.z, z) != 0) return false;
if (!name.equals(bdbPlace.name)) return false;
return true;
}
@Override
public int hashCode() {
return (int) (id ^ (id >>> 32));
}
}

View File

@@ -4,7 +4,7 @@ import com.sleepycat.persist.model.*;
import ru.trader.core.SERVICE_TYPE;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashSet;
@Entity(version = 1)
public class BDBVendor {
@@ -13,14 +13,13 @@ public class BDBVendor {
private long id;
@SecondaryKey(relate = Relationship.MANY_TO_ONE,
relatedEntity = BDBPlace.class,
onRelatedEntityDelete = DeleteAction.NULLIFY)
relatedEntity = BDBPlace.class, onRelatedEntityDelete = DeleteAction.CASCADE)
private long placeId;
private String name;
private double distance;
@SecondaryKey(relate=Relationship.ONE_TO_MANY)
EnumSet<SERVICE_TYPE> services = EnumSet.noneOf(SERVICE_TYPE.class);
@SecondaryKey(relate=Relationship.MANY_TO_MANY)
Collection<SERVICE_TYPE> services = new HashSet<>();
private BDBVendor() {
}
@@ -73,4 +72,25 @@ public class BDBVendor {
public Collection<SERVICE_TYPE> getServices() {
return services;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BDBVendor)) return false;
BDBVendor bdbVendor = (BDBVendor) o;
if (Double.compare(bdbVendor.distance, distance) != 0) return false;
if (id != bdbVendor.id) return false;
if (placeId != bdbVendor.placeId) return false;
if (!name.equals(bdbVendor.name)) return false;
if (!services.equals(bdbVendor.services)) return false;
return true;
}
@Override
public int hashCode() {
return (int) (id ^ (id >>> 32));
}
}