This commit is contained in:
Sean Mullan 2012-06-15 08:47:41 -04:00
commit caae78ba73
11 changed files with 371 additions and 172 deletions

View file

@ -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())
) {
ResultSetMetaData rsmd = crs.getMetaData();
int icolCount = rsmd.getColumnCount();
String[] primaryKeys = new String[icolCount]; 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;
}
} }

View file

@ -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()));
} }

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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.

View file

@ -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++;

View file

@ -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;

View file

@ -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

View 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();
}
}
}

View file

@ -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();
}
} }
} }