package com.tesora.dve.db.mysql; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import com.tesora.dve.common.PECollectionUtils; import com.tesora.dve.common.catalog.StorageSite; import com.tesora.dve.db.CommandChannel; import com.tesora.dve.db.mysql.libmy.MyBinaryResultRow; import com.tesora.dve.db.mysql.libmy.MyErrorResponse; import com.tesora.dve.db.mysql.libmy.MyOKResponse; import com.tesora.dve.db.mysql.portal.protocol.CanFlowControl; import com.tesora.dve.db.mysql.portal.protocol.DownstreamFlowControlSet; import com.tesora.dve.db.mysql.portal.protocol.FlowControl; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.server.messaging.SQLCommand; import com.tesora.dve.worker.Worker; import com.tesora.dve.worker.WorkerGroup; import java.util.*; /** * */ public class RedistTargetSet implements RedistTargetSite.InsertWatcher, RedistTargetSite.InsertPolicy, CanFlowControl { final WorkerGroup targetWG; final RedistTargetSite.InsertWatcher watcher; RedistTargetSite.InsertPolicy policy; final Map<StorageSite, RedistTargetSite> siteCtxBySite = new HashMap<>(); final DownstreamFlowControlSet siteFlowControl = new DownstreamFlowControlSet(); boolean alreadyFailed = false; boolean alreadyClosed = false; long insertedRows = 0; public RedistTargetSet(WorkerGroup targetWG, RedistTargetSite.InsertWatcher watcher, RedistTargetSite.InsertPolicy policy, FlowControl sourceControl) throws PEException { this.targetWG = targetWG; this.watcher = watcher; this.policy = policy; siteFlowControl.setUpstreamControl(sourceControl); Collection<Worker> targetWorkers = targetWG.getTargetWorkers(WorkerGroup.MappingSolution.AllWorkers); for (Worker targetWorker : targetWorkers){ CommandChannel directChannel = targetWorker.getDirectChannel(); StorageSite site = directChannel.getStorageSite(); RedistTargetSite siteCtx = new RedistTargetSite(this, directChannel, this); siteFlowControl.register(siteCtx); siteCtxBySite.put(site, siteCtx); } } public boolean sendInsert(WorkerGroup.MappingSolution mappingSolution, MyBinaryResultRow binRow) throws PEException { if (alreadyFailed || alreadyClosed) return false; Collection<RedistTargetSite> allTargetSites = chooseTargetSites(mappingSolution); boolean flushedOne = false; for (RedistTargetSite siteCtx : allTargetSites) { flushedOne = flushedOne || siteCtx.append(binRow); } return flushedOne; } private Collection<RedistTargetSite> chooseTargetSites(WorkerGroup.MappingSolution mappingSolution) throws PEException { Collection<RedistTargetSite> allTargetSites; if (mappingSolution == WorkerGroup.MappingSolution.AllWorkers || mappingSolution == WorkerGroup.MappingSolution.AllWorkersSerialized) { //this is broadcast, we send to all workers. allTargetSites = siteCtxBySite.values(); } else if (mappingSolution == WorkerGroup.MappingSolution.AnyWorker || mappingSolution == WorkerGroup.MappingSolution.AnyWorkerSerialized) { //this is random, we send to any of the workers. allTargetSites = Collections.singleton(PECollectionUtils.selectRandom(siteCtxBySite.values())); } else { //this is range, we send to a specific worker based on the previously computed distribution vector of the row allTargetSites = Collections.singleton(siteCtxBySite.get(targetWG.resolveSite(mappingSolution.getSite()))); } return allTargetSites; } public void close() { for (RedistTargetSite siteCtx : siteCtxBySite.values()) { siteCtx.close(); siteFlowControl.unregister(siteCtx); } alreadyClosed = true; } public void flush() { for (RedistTargetSite siteContext : siteCtxBySite.values()) { siteContext.flush(); } } public boolean hasPendingRows() { boolean anySiteHasPending = false; for (RedistTargetSite siteCtx : siteCtxBySite.values()) { if (siteCtx.hasPendingRows()){ anySiteHasPending = true; break; } } return anySiteHasPending; } @Override public int getMaximumRowsToBuffer() { return policy.getMaximumRowsToBuffer(); } @Override public long getMaximumBytesToBuffer() { return policy.getMaximumBytesToBuffer(); } @Override public int getColumnsPerTuple() { return policy.getColumnsPerTuple(); } @Override public SQLCommand buildInsertStatement(int tupleCount) throws PEException { return policy.buildInsertStatement(tupleCount); } @Override public void insertOK(RedistTargetSite siteCtx, MyOKResponse okPacket) { if (alreadyFailed || alreadyClosed) return; long affectedRows = okPacket.getAffectedRows(); try { int rowCount = (int) affectedRows; insertedRows += rowCount; } finally { watcher.insertOK(siteCtx,okPacket); } } @Override public void insertFailed(RedistTargetSite site, MyErrorResponse errorPacket) { this.alreadyFailed = true; watcher.insertFailed(site,errorPacket); } @Override public void insertFailed(RedistTargetSite site, Exception e) { this.alreadyFailed = true; watcher.insertFailed(site,e); } public long getUpdatedRowCount() { return insertedRows; } @Override public void setUpstreamControl(FlowControl control) { if (control == this || control == siteFlowControl) throw new IllegalArgumentException(); siteFlowControl.setUpstreamControl(control); } }