mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-23 12:34:32 +02:00
Merge
This commit is contained in:
commit
caae78ba73
11 changed files with 371 additions and 172 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -828,39 +828,55 @@ public class CachedRowSetWriter implements TransactionalWriter, Serializable {
|
||||||
*/
|
*/
|
||||||
private boolean insertNewRow(CachedRowSet crs,
|
private boolean insertNewRow(CachedRowSet crs,
|
||||||
PreparedStatement pstmt, CachedRowSetImpl crsRes) throws SQLException {
|
PreparedStatement pstmt, CachedRowSetImpl crsRes) throws SQLException {
|
||||||
int i = 0;
|
|
||||||
int icolCount = crs.getMetaData().getColumnCount();
|
|
||||||
|
|
||||||
boolean returnVal = false;
|
boolean returnVal = false;
|
||||||
PreparedStatement pstmtSel = con.prepareStatement(selectCmd,
|
|
||||||
ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
try (PreparedStatement pstmtSel = con.prepareStatement(selectCmd,
|
||||||
ResultSet rs, rs2 = null;
|
ResultSet.TYPE_SCROLL_SENSITIVE,
|
||||||
DatabaseMetaData dbmd = con.getMetaData();
|
ResultSet.CONCUR_READ_ONLY);
|
||||||
rs = pstmtSel.executeQuery();
|
ResultSet rs = pstmtSel.executeQuery();
|
||||||
String table = crs.getTableName();
|
ResultSet rs2 = con.getMetaData().getPrimaryKeys(null, null,
|
||||||
rs2 = dbmd.getPrimaryKeys(null, null, table);
|
crs.getTableName())
|
||||||
String [] primaryKeys = new String[icolCount];
|
) {
|
||||||
|
|
||||||
|
ResultSetMetaData rsmd = crs.getMetaData();
|
||||||
|
int icolCount = rsmd.getColumnCount();
|
||||||
|
String[] primaryKeys = new String[icolCount];
|
||||||
int k = 0;
|
int k = 0;
|
||||||
while(rs2.next()) {
|
while (rs2.next()) {
|
||||||
String pkcolname = rs2.getString("COLUMN_NAME");
|
primaryKeys[k] = rs2.getString("COLUMN_NAME");
|
||||||
primaryKeys[k] = pkcolname;
|
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rs.next()) {
|
if (rs.next()) {
|
||||||
for(int j=0;j<primaryKeys.length;j++) {
|
for (String pkName : primaryKeys) {
|
||||||
if(primaryKeys[j] != null) {
|
if (!isPKNameValid(pkName, rsmd)) {
|
||||||
if(crs.getObject(primaryKeys[j]) == null){
|
|
||||||
|
/* We came here as one of the the primary keys
|
||||||
|
* of the table is not present in the cached
|
||||||
|
* rowset object, it should be an autoincrement column
|
||||||
|
* and not included while creating CachedRowSet
|
||||||
|
* Object, proceed to check for other primary keys
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object crsPK = crs.getObject(pkName);
|
||||||
|
if (crsPK == null) {
|
||||||
|
/*
|
||||||
|
* It is possible that the PK is null on some databases
|
||||||
|
* and will be filled in at insert time (MySQL for example)
|
||||||
|
*/
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
String crsPK = (crs.getObject(primaryKeys[j])).toString();
|
|
||||||
String rsPK = (rs.getObject(primaryKeys[j])).toString();
|
String rsPK = rs.getObject(pkName).toString();
|
||||||
if(crsPK.equals(rsPK)) {
|
if (crsPK.toString().equals(rsPK)) {
|
||||||
returnVal = true;
|
returnVal = true;
|
||||||
this.crsResolve.moveToInsertRow();
|
this.crsResolve.moveToInsertRow();
|
||||||
for(i = 1; i <= icolCount; i++) {
|
for (int i = 1; i <= icolCount; i++) {
|
||||||
String colname = (rs.getMetaData()).getColumnName(i);
|
String colname = (rs.getMetaData()).getColumnName(i);
|
||||||
if(colname.equals(primaryKeys[j]))
|
if (colname.equals(pkName))
|
||||||
this.crsResolve.updateObject(i,rsPK);
|
this.crsResolve.updateObject(i,rsPK);
|
||||||
else
|
else
|
||||||
this.crsResolve.updateNull(i);
|
this.crsResolve.updateNull(i);
|
||||||
|
@ -870,12 +886,13 @@ public class CachedRowSetWriter implements TransactionalWriter, Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(returnVal)
|
if (returnVal) {
|
||||||
return returnVal;
|
return returnVal;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (i = 1; i <= icolCount; i++) {
|
for (int i = 1; i <= icolCount; i++) {
|
||||||
Object obj = crs.getObject(i);
|
Object obj = crs.getObject(i);
|
||||||
if (obj != null) {
|
if (obj != null) {
|
||||||
pstmt.setObject(i, obj);
|
pstmt.setObject(i, obj);
|
||||||
|
@ -884,20 +901,20 @@ public class CachedRowSetWriter implements TransactionalWriter, Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i = pstmt.executeUpdate();
|
pstmt.executeUpdate();
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
/**
|
/*
|
||||||
* Cursor will come here if executeUpdate fails.
|
* Cursor will come here if executeUpdate fails.
|
||||||
* There can be many reasons why the insertion failed,
|
* There can be many reasons why the insertion failed,
|
||||||
* one can be violation of primary key.
|
* one can be violation of primary key.
|
||||||
* Hence we cannot exactly identify why the insertion failed
|
* Hence we cannot exactly identify why the insertion failed,
|
||||||
* Present the current row as a null row to the user.
|
* present the current row as a null row to the caller.
|
||||||
**/
|
*/
|
||||||
this.crsResolve.moveToInsertRow();
|
this.crsResolve.moveToInsertRow();
|
||||||
|
|
||||||
for(i = 1; i <= icolCount; i++) {
|
for (int i = 1; i <= icolCount; i++) {
|
||||||
this.crsResolve.updateNull(i);
|
this.crsResolve.updateNull(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -907,6 +924,7 @@ public class CachedRowSetWriter implements TransactionalWriter, Serializable {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the row in the underlying data source that corresponds to
|
* Deletes the row in the underlying data source that corresponds to
|
||||||
|
@ -1437,4 +1455,25 @@ public class CachedRowSetWriter implements TransactionalWriter, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
static final long serialVersionUID =-8506030970299413976L;
|
static final long serialVersionUID =-8506030970299413976L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate whether the Primary Key is known to the CachedRowSet. If it is
|
||||||
|
* not, it is an auto-generated key
|
||||||
|
* @param pk - Primary Key to validate
|
||||||
|
* @param rsmd - ResultSetMetadata for the RowSet
|
||||||
|
* @return true if found, false otherwise (auto generated key)
|
||||||
|
*/
|
||||||
|
private boolean isPKNameValid(String pk, ResultSetMetaData rsmd) throws SQLException {
|
||||||
|
boolean isValid = false;
|
||||||
|
int cols = rsmd.getColumnCount();
|
||||||
|
for(int i = 1; i<= cols; i++) {
|
||||||
|
String colName = rsmd.getColumnClassName(i);
|
||||||
|
if(colName.equalsIgnoreCase(pk)) {
|
||||||
|
isValid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -764,6 +764,7 @@ public class XmlReaderContentHandler extends DefaultHandler {
|
||||||
rs.next();
|
rs.next();
|
||||||
rs.setOriginalRow();
|
rs.setOriginalRow();
|
||||||
applyUpdates();
|
applyUpdates();
|
||||||
|
rs.deleteRow();
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errdel").toString() , ex.getMessage()));
|
throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errdel").toString() , ex.getMessage()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -288,12 +288,11 @@ public class HashMap<K,V>
|
||||||
* in lower bits.
|
* in lower bits.
|
||||||
*/
|
*/
|
||||||
final int hash(Object k) {
|
final int hash(Object k) {
|
||||||
int h = hashSeed;
|
|
||||||
if (k instanceof String) {
|
if (k instanceof String) {
|
||||||
return ((String)k).hash32();
|
return ((String) k).hash32();
|
||||||
}
|
}
|
||||||
|
|
||||||
h ^= k.hashCode();
|
int h = hashSeed ^ k.hashCode();
|
||||||
|
|
||||||
// This function ensures that hashCodes that differ only by
|
// This function ensures that hashCodes that differ only by
|
||||||
// constant multiples at each bit position have a bounded
|
// constant multiples at each bit position have a bounded
|
||||||
|
|
|
@ -194,12 +194,11 @@ public class Hashtable<K,V>
|
||||||
transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this);
|
transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this);
|
||||||
|
|
||||||
private int hash(Object k) {
|
private int hash(Object k) {
|
||||||
int h = hashSeed;
|
|
||||||
|
|
||||||
if (k instanceof String) {
|
if (k instanceof String) {
|
||||||
return ((String)k).hash32();
|
return ((String)k).hash32();
|
||||||
} else {
|
}
|
||||||
h ^= k.hashCode();
|
|
||||||
|
int h = hashSeed ^ k.hashCode();
|
||||||
|
|
||||||
// This function ensures that hashCodes that differ only by
|
// This function ensures that hashCodes that differ only by
|
||||||
// constant multiples at each bit position have a bounded
|
// constant multiples at each bit position have a bounded
|
||||||
|
@ -207,7 +206,6 @@ public class Hashtable<K,V>
|
||||||
h ^= (h >>> 20) ^ (h >>> 12);
|
h ^= (h >>> 20) ^ (h >>> 12);
|
||||||
return h ^ (h >>> 7) ^ (h >>> 4);
|
return h ^ (h >>> 7) ^ (h >>> 4);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new, empty hashtable with the specified initial
|
* Constructs a new, empty hashtable with the specified initial
|
||||||
|
@ -1015,7 +1013,7 @@ public class Hashtable<K,V>
|
||||||
*/
|
*/
|
||||||
private static class Entry<K,V> implements Map.Entry<K,V> {
|
private static class Entry<K,V> implements Map.Entry<K,V> {
|
||||||
final int hash;
|
final int hash;
|
||||||
K key;
|
final K key;
|
||||||
V value;
|
V value;
|
||||||
Entry<K,V> next;
|
Entry<K,V> next;
|
||||||
|
|
||||||
|
|
|
@ -295,13 +295,11 @@ public class WeakHashMap<K,V>
|
||||||
* otherwise encounter collisions for hashCodes that do not differ
|
* otherwise encounter collisions for hashCodes that do not differ
|
||||||
* in lower bits.
|
* in lower bits.
|
||||||
*/
|
*/
|
||||||
int hash(Object k) {
|
final int hash(Object k) {
|
||||||
int h = hashSeed;
|
|
||||||
if (k instanceof String) {
|
if (k instanceof String) {
|
||||||
return ((String) k).hash32();
|
return ((String) k).hash32();
|
||||||
} else {
|
|
||||||
h ^= k.hashCode();
|
|
||||||
}
|
}
|
||||||
|
int h = hashSeed ^ k.hashCode();
|
||||||
|
|
||||||
// This function ensures that hashCodes that differ only by
|
// This function ensures that hashCodes that differ only by
|
||||||
// constant multiples at each bit position have a bounded
|
// constant multiples at each bit position have a bounded
|
||||||
|
|
|
@ -269,13 +269,11 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
|
||||||
* differ in lower or upper bits.
|
* differ in lower or upper bits.
|
||||||
*/
|
*/
|
||||||
private int hash(Object k) {
|
private int hash(Object k) {
|
||||||
int h = hashSeed;
|
|
||||||
|
|
||||||
if (k instanceof String) {
|
if (k instanceof String) {
|
||||||
return ((String) k).hash32();
|
return ((String) k).hash32();
|
||||||
}
|
}
|
||||||
|
|
||||||
h ^= k.hashCode();
|
int h = hashSeed ^ k.hashCode();
|
||||||
|
|
||||||
// Spread bits to regularize both segment and index locations,
|
// Spread bits to regularize both segment and index locations,
|
||||||
// using variant of single-word Wang/Jenkins hash.
|
// using variant of single-word Wang/Jenkins hash.
|
||||||
|
|
|
@ -120,7 +120,7 @@ typedef struct LookupTable {
|
||||||
TableIndex table_incr; /* Suggested increment size. */
|
TableIndex table_incr; /* Suggested increment size. */
|
||||||
TableIndex hash_bucket_count; /* Number of hash buckets. */
|
TableIndex hash_bucket_count; /* Number of hash buckets. */
|
||||||
int elem_size; /* Size of element. */
|
int elem_size; /* Size of element. */
|
||||||
int info_size; /* Size of info structure. */
|
int info_size; /* Size of info structure (can be 0). */
|
||||||
void *freed_bv; /* Freed element bit vector */
|
void *freed_bv; /* Freed element bit vector */
|
||||||
int freed_count; /* Count of freed'd elements */
|
int freed_count; /* Count of freed'd elements */
|
||||||
TableIndex freed_start; /* First freed in table */
|
TableIndex freed_start; /* First freed in table */
|
||||||
|
@ -208,9 +208,6 @@ get_info(LookupTable *ltable, TableIndex index)
|
||||||
{
|
{
|
||||||
TableElement *element;
|
TableElement *element;
|
||||||
|
|
||||||
if ( ltable->info_size == 0 ) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
element = (TableElement*)ELEMENT_PTR(ltable,index);
|
element = (TableElement*)ELEMENT_PTR(ltable,index);
|
||||||
return element->info;
|
return element->info;
|
||||||
}
|
}
|
||||||
|
@ -760,7 +757,11 @@ table_walk_items(LookupTable *ltable, LookupTableIterator func, void* arg)
|
||||||
void *info;
|
void *info;
|
||||||
|
|
||||||
get_key(ltable, index, &key_ptr, &key_len);
|
get_key(ltable, index, &key_ptr, &key_len);
|
||||||
|
if ( ltable->info_size == 0 ) {
|
||||||
|
info = NULL;
|
||||||
|
} else {
|
||||||
info = get_info(ltable, index);
|
info = get_info(ltable, index);
|
||||||
|
}
|
||||||
(*func)(SANITY_ADD_HARE(index, ltable->hare), key_ptr, key_len, info, arg);
|
(*func)(SANITY_ADD_HARE(index, ltable->hare), key_ptr, key_len, info, arg);
|
||||||
if ( is_freed_entry(ltable, index) ) {
|
if ( is_freed_entry(ltable, index) ) {
|
||||||
fcount++;
|
fcount++;
|
||||||
|
|
|
@ -119,9 +119,13 @@ md_connect(char *hostname, unsigned short port)
|
||||||
|
|
||||||
/* create a socket */
|
/* create a socket */
|
||||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if ( fd < 0 ) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* find remote host's addr from name */
|
/* find remote host's addr from name */
|
||||||
if ((hentry = gethostbyname(hostname)) == NULL) {
|
if ((hentry = gethostbyname(hostname)) == NULL) {
|
||||||
|
(void)close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
(void)memset((char *)&s, 0, sizeof(s));
|
(void)memset((char *)&s, 0, sizeof(s));
|
||||||
|
@ -134,6 +138,7 @@ md_connect(char *hostname, unsigned short port)
|
||||||
|
|
||||||
/* now try connecting */
|
/* now try connecting */
|
||||||
if (-1 == connect(fd, (struct sockaddr*)&s, sizeof(s))) {
|
if (-1 == connect(fd, (struct sockaddr*)&s, sizeof(s))) {
|
||||||
|
(void)close(fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return fd;
|
return fd;
|
||||||
|
|
|
@ -141,15 +141,18 @@ Java_sun_nio_ch_SocketDispatcher_readv0(JNIEnv *env, jclass clazz, jobject fdo,
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_sun_nio_ch_SocketDispatcher_write0(JNIEnv *env, jclass clazz, jobject fdo,
|
Java_sun_nio_ch_SocketDispatcher_write0(JNIEnv *env, jclass clazz, jobject fdo,
|
||||||
jlong address, jint len)
|
jlong address, jint total)
|
||||||
{
|
{
|
||||||
/* set up */
|
/* set up */
|
||||||
int i = 0;
|
int i = 0;
|
||||||
DWORD written = 0;
|
DWORD written = 0;
|
||||||
|
jint count = 0;
|
||||||
jint fd = fdval(env, fdo);
|
jint fd = fdval(env, fdo);
|
||||||
WSABUF buf;
|
WSABUF buf;
|
||||||
|
|
||||||
|
do {
|
||||||
/* limit size */
|
/* limit size */
|
||||||
|
jint len = total - count;
|
||||||
if (len > MAX_BUFFER_SIZE)
|
if (len > MAX_BUFFER_SIZE)
|
||||||
len = MAX_BUFFER_SIZE;
|
len = MAX_BUFFER_SIZE;
|
||||||
|
|
||||||
|
@ -157,7 +160,7 @@ Java_sun_nio_ch_SocketDispatcher_write0(JNIEnv *env, jclass clazz, jobject fdo,
|
||||||
buf.buf = (char *)address;
|
buf.buf = (char *)address;
|
||||||
buf.len = (u_long)len;
|
buf.len = (u_long)len;
|
||||||
|
|
||||||
/* read into the buffers */
|
/* write from the buffer */
|
||||||
i = WSASend((SOCKET)fd, /* Socket */
|
i = WSASend((SOCKET)fd, /* Socket */
|
||||||
&buf, /* pointers to the buffers */
|
&buf, /* pointers to the buffers */
|
||||||
(DWORD)1, /* number of buffers to process */
|
(DWORD)1, /* number of buffers to process */
|
||||||
|
@ -167,6 +170,10 @@ Java_sun_nio_ch_SocketDispatcher_write0(JNIEnv *env, jclass clazz, jobject fdo,
|
||||||
0); /* no completion routine */
|
0); /* no completion routine */
|
||||||
|
|
||||||
if (i == SOCKET_ERROR) {
|
if (i == SOCKET_ERROR) {
|
||||||
|
if (count > 0) {
|
||||||
|
/* can't throw exception when some bytes have been written */
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
int theErr = (jint)WSAGetLastError();
|
int theErr = (jint)WSAGetLastError();
|
||||||
if (theErr == WSAEWOULDBLOCK) {
|
if (theErr == WSAEWOULDBLOCK) {
|
||||||
return IOS_UNAVAILABLE;
|
return IOS_UNAVAILABLE;
|
||||||
|
@ -174,8 +181,14 @@ Java_sun_nio_ch_SocketDispatcher_write0(JNIEnv *env, jclass clazz, jobject fdo,
|
||||||
JNU_ThrowIOExceptionWithLastError(env, "Write failed");
|
JNU_ThrowIOExceptionWithLastError(env, "Write failed");
|
||||||
return IOS_THROWN;
|
return IOS_THROWN;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return convertReturnVal(env, (jint)written, JNI_FALSE);
|
count += written;
|
||||||
|
address += written;
|
||||||
|
|
||||||
|
} while ((count < total) && (written == MAX_BUFFER_SIZE));
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
|
|
136
jdk/test/java/nio/channels/SocketChannel/ShortWrite.java
Normal file
136
jdk/test/java/nio/channels/SocketChannel/ShortWrite.java
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code 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 General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @test
|
||||||
|
* @bug 7176630
|
||||||
|
* @summary Check for short writes on SocketChannels configured in blocking mode
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
|
public class ShortWrite {
|
||||||
|
|
||||||
|
static final Random rand = new Random();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a checksum on the remaining bytes in the given buffer.
|
||||||
|
*/
|
||||||
|
static long computeChecksum(ByteBuffer bb) {
|
||||||
|
CRC32 crc32 = new CRC32();
|
||||||
|
crc32.update(bb);
|
||||||
|
return crc32.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A task that reads the expected number of bytes and returns the CRC32
|
||||||
|
* of those bytes.
|
||||||
|
*/
|
||||||
|
static class Reader implements Callable<Long> {
|
||||||
|
final SocketChannel sc;
|
||||||
|
final ByteBuffer buf;
|
||||||
|
|
||||||
|
Reader(SocketChannel sc, int expectedSize) {
|
||||||
|
this.sc = sc;
|
||||||
|
this.buf = ByteBuffer.allocate(expectedSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long call() throws Exception {
|
||||||
|
while (buf.hasRemaining()) {
|
||||||
|
int n = sc.read(buf);
|
||||||
|
if (n == -1)
|
||||||
|
throw new RuntimeException("Premature EOF encountered");
|
||||||
|
}
|
||||||
|
buf.flip();
|
||||||
|
return computeChecksum(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run test with a write of the given number of bytes.
|
||||||
|
*/
|
||||||
|
static void test(ExecutorService pool,
|
||||||
|
SocketChannel source,
|
||||||
|
SocketChannel sink,
|
||||||
|
int size)
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
System.out.println(size);
|
||||||
|
|
||||||
|
// random bytes in the buffer
|
||||||
|
ByteBuffer buf = ByteBuffer.allocate(size);
|
||||||
|
rand.nextBytes(buf.array());
|
||||||
|
|
||||||
|
// submit task to read the bytes
|
||||||
|
Future<Long> result = pool.submit(new Reader(sink, size));
|
||||||
|
|
||||||
|
// write the bytes
|
||||||
|
int n = source.write(buf);
|
||||||
|
if (n != size)
|
||||||
|
throw new RuntimeException("Short write detected");
|
||||||
|
|
||||||
|
// check the bytes that were received match
|
||||||
|
buf.rewind();
|
||||||
|
long expected = computeChecksum(buf);
|
||||||
|
long actual = result.get();
|
||||||
|
if (actual != expected)
|
||||||
|
throw new RuntimeException("Checksum did not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
ExecutorService pool = Executors.newSingleThreadExecutor();
|
||||||
|
try {
|
||||||
|
try (ServerSocketChannel ssc = ServerSocketChannel.open()) {
|
||||||
|
ssc.bind(new InetSocketAddress(0));
|
||||||
|
InetAddress lh = InetAddress.getLocalHost();
|
||||||
|
int port = ssc.socket().getLocalPort();
|
||||||
|
SocketAddress sa = new InetSocketAddress(lh, port);
|
||||||
|
|
||||||
|
try (SocketChannel source = SocketChannel.open(sa);
|
||||||
|
SocketChannel sink = ssc.accept())
|
||||||
|
{
|
||||||
|
// run tests on sizes around 128k as that is the problem
|
||||||
|
// area on Windows.
|
||||||
|
int BOUNDARY = 128 * 1024;
|
||||||
|
for (int size=(BOUNDARY-2); size<=(BOUNDARY+2); size++) {
|
||||||
|
test(pool, source, sink, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// run tests on random sizes
|
||||||
|
for (int i=0; i<20; i++) {
|
||||||
|
int size = rand.nextInt(1024*1024);
|
||||||
|
test(pool, source, sink, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
pool.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,8 +48,14 @@ public class TcpTimeout {
|
||||||
k.addPrincipalRandKey("krbtgt/" + OneKDC.REALM);
|
k.addPrincipalRandKey("krbtgt/" + OneKDC.REALM);
|
||||||
|
|
||||||
// Start two listener that does not communicate, simulate timeout
|
// Start two listener that does not communicate, simulate timeout
|
||||||
int p1 = new ServerSocket(0).getLocalPort();
|
ServerSocket ss1 = null;
|
||||||
int p2 = new ServerSocket(0).getLocalPort();
|
ServerSocket ss2 = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
ss1 = new ServerSocket(0);
|
||||||
|
ss2 = new ServerSocket(0);
|
||||||
|
int p1 = ss1.getLocalPort();
|
||||||
|
int p2 = ss2.getLocalPort();
|
||||||
|
|
||||||
FileWriter fw = new FileWriter("alternative-krb5.conf");
|
FileWriter fw = new FileWriter("alternative-krb5.conf");
|
||||||
|
|
||||||
|
@ -65,7 +71,8 @@ public class TcpTimeout {
|
||||||
"}\n");
|
"}\n");
|
||||||
|
|
||||||
fw.close();
|
fw.close();
|
||||||
System.setProperty("java.security.krb5.conf", "alternative-krb5.conf");
|
System.setProperty("java.security.krb5.conf",
|
||||||
|
"alternative-krb5.conf");
|
||||||
Config.refresh();
|
Config.refresh();
|
||||||
|
|
||||||
System.out.println("Ports opened on " + p1 + ", " + p2 + ", " + p3);
|
System.out.println("Ports opened on " + p1 + ", " + p2 + ", " + p3);
|
||||||
|
@ -92,5 +99,9 @@ public class TcpTimeout {
|
||||||
if (count != 0) {
|
if (count != 0) {
|
||||||
throw new Exception("Retry count is " + count + " less");
|
throw new Exception("Retry count is " + count + " less");
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
if (ss1 != null) ss1.close();
|
||||||
|
if (ss2 != null) ss2.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue