package com.tesora.dve.sql;
/*
* #%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 io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.apache.commons.lang.StringUtils;
import org.junit.AfterClass;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import org.testng.Assert;
import com.tesora.dve.db.mysql.portal.protocol.MSPComQueryRequestMessage;
import com.tesora.dve.db.mysql.portal.protocol.Packet;
import com.tesora.dve.sql.util.MirrorTest;
import com.tesora.dve.sql.util.NativeDDL;
import com.tesora.dve.sql.util.PEDDL;
import com.tesora.dve.sql.util.ProjectDDL;
import com.tesora.dve.sql.util.StorageGroupDDL;
import com.tesora.dve.worker.WorkerGroup.WorkerGroupFactory;
public class LargeMaxPktTest extends SchemaMirrorTest {
private static final int SITES = 5;
private static final ProjectDDL sysDDL = new PEDDL("sysdb",
new StorageGroupDDL("sys",SITES,"sysg"),
"schema");
static final NativeDDL nativeDDL = new NativeDDL("cdb");
@Override
protected ProjectDDL getMultiDDL() {
return sysDDL;
}
@Override
protected ProjectDDL getNativeDDL() {
return nativeDDL;
}
@BeforeClass
public static void setup() throws Throwable {
// in order to change the max_allowed_packet properly, we need to make sure we don't cache backend connections
// that could contain the old value
setup(sysDDL,null,nativeDDL,getSchema());
WorkerGroupFactory.suppressCaching();
}
@AfterClass
public static void cleanup() throws Throwable {
WorkerGroupFactory.restoreCaching();
}
private static List<MirrorTest> getSchema() {
ArrayList<MirrorTest> out = new ArrayList<MirrorTest>();
return out;
}
@Test
public void testPE1512() throws Throwable {
final ExtendedPacketTester tester = new ExtendedPacketTester(67108864);
tester.add(new StatementMirrorProc("CREATE TABLE `pe1512` (`data` longblob)"));
tester.add(new StatementMirrorProc("INSERT INTO `pe1512` VALUES ('" + StringUtils.repeat("0", 17000000) + "')"));
tester.add(new StatementMirrorFun("SELECT length(data) FROM `pe1512`"));
tester.add(new StatementMirrorFun("SELECT data FROM `pe1512`"));
tester.runTests();
}
@Test
public void testPE1559() throws Throwable {
try {
// final String payload = FileUtils.readFileToString(getFileFromLargeFileRepository("pe1559_payload.dat"));
int desiredLength = 34000000;
Assume.assumeTrue("Didn't have enough memory to be confident test would run, skipped.", Runtime.getRuntime().maxMemory() >= (desiredLength * 20L));
final String payload = largeRandomString("testPE1559", desiredLength); //two full extended packets, plus ~500K
final ExtendedPacketTester tester = new ExtendedPacketTester(67108864);
tester.add(new StatementMirrorProc(
"CREATE TABLE `cache_views` ("
+ "`cid` varchar(255) NOT NULL DEFAULT '',"
+ "`data` longblob,"
+ "`expire` int(11) NOT NULL DEFAULT '0',"
+ "`created` int(11) NOT NULL DEFAULT '0',"
+ "`serialized` smallint(6) NOT NULL DEFAULT '0',"
+ "PRIMARY KEY (`cid`),"
+ "KEY `expire` (`expire`)"
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 /*#dve BROADCAST DISTRIBUTE */"));
tester.add(new StatementMirrorProc("INSERT INTO `cache_views` (cid) VALUES ('views_data:en')"));
tester.add(new StatementMirrorProc("UPDATE `cache_views` SET serialized='1', created='1403888529', expire='0', data='"
+ payload + "' WHERE (cid = 'views_data:en')"));
tester.add(new StatementMirrorFun("SELECT length(data) FROM `cache_views`"));
tester.add(new StatementMirrorFun("SELECT data FROM `cache_views`"));
tester.runTests();
} catch (final LargeTestResourceNotAvailableException e) {
System.err.println("WARNING: This test will be ignored: " + e.getMessage());
return;
}
}
private String largeRandomString(String testName, int desiredLength) throws LargeTestResourceNotAvailableException {
Random rand = new Random(938398373L); //fix the seed, so we always generate the same string.
StringBuilder builder = new StringBuilder(desiredLength);
int remainingChars = desiredLength;
while (remainingChars > 0){
char entry = (char)('a' + rand.nextInt(26));//this generates only ASCII lowercase 'a' through 'z'.
builder.append(entry);
remainingChars--;
}
// final String payload = FileUtils.readFileToString(getFileFromLargeFileRepository("pe1559_payload.dat"));
final String payload = builder.toString();
return payload;
}
@Test
public void testComQueryMessageContinuationOverlap() throws Exception {
int defaultMaxPacket = 0xFFFFFF;
int payloadSize = (defaultMaxPacket * 4) + (4 * 40); //four full packets and a little change, divisible by 4.
ByteBuf source = Unpooled.buffer(payloadSize,payloadSize);
Random rand = new Random(239873L);
while (source.isWritable())
source.writeInt(rand.nextInt());
Assert.assertEquals(source.writableBytes(),0,"Oops, I intended to fill up the source buffer");
ByteBuf dest = Unpooled.buffer(payloadSize);
MSPComQueryRequestMessage outboundMessage = MSPComQueryRequestMessage.newMessage(source.array() );
Packet.encodeFullMessage((byte)0, outboundMessage, dest);
int lengthOfNonUserdata = 5 + 4 + 4 + 4 + 4;
Assert.assertEquals(dest.readableBytes(),payloadSize + lengthOfNonUserdata,"Number of bytes in destination buffer is wrong");
Assert.assertEquals(dest.getUnsignedMedium(0),defaultMaxPacket,"First length should be maximum");
Assert.assertEquals(dest.getByte(3),(byte)0,"First sequenceID should be zero");
Assert.assertEquals(dest.getByte(4),(byte)MSPComQueryRequestMessage.TYPE_IDENTIFIER,"First byte of payload should be MSPComQueryRequestMessage.TYPE_IDENTIFIER");
ByteBuf sliceFirstPayload = dest.slice(5, (0xFFFFFF - 1));
Assert.assertEquals(sliceFirstPayload,source.slice(0,0xFFFFFF - 1));
}
@Test
public void testComQueryMessageContinuationExact() throws Exception {
int defaultMaxPacket = 0xFFFFFF;
int payloadSize = (defaultMaxPacket * 4); //four full packets exactly, requires an empty trailing packet.
ByteBuf source = Unpooled.buffer(payloadSize,payloadSize);
Random rand = new Random(239873L);
while (source.isWritable())
source.writeInt(rand.nextInt());
Assert.assertEquals(source.writableBytes(),0,"Oops, I intended to fill up the source buffer");
ByteBuf dest = Unpooled.buffer(payloadSize);
MSPComQueryRequestMessage outboundMessage = MSPComQueryRequestMessage.newMessage(source.array() );
Packet.encodeFullMessage((byte)0, outboundMessage, dest);
int lengthOfNonUserdata = 5 + 4 + 4 + 4 + 4;//last packet has zero length payload
Assert.assertEquals(dest.readableBytes(),payloadSize + lengthOfNonUserdata,"Number of bytes in destination buffer is wrong");
Assert.assertEquals(dest.getUnsignedMedium(0),defaultMaxPacket,"First length should be maximum");
Assert.assertEquals(dest.getByte(3),(byte)0,"First sequenceID should be zero");
Assert.assertEquals(dest.getByte(4),(byte)MSPComQueryRequestMessage.TYPE_IDENTIFIER,"First byte of payload should be MSPComQueryRequestMessage.TYPE_IDENTIFIER");
ByteBuf sliceFirstPayload = dest.slice(5, (0xFFFFFF - 1));
Assert.assertEquals(sliceFirstPayload,source.slice(0,0xFFFFFF - 1));
}
}