Generalized Method Argument Arrays and XML

Today I finished generalizing the annotations that pass method arguments as arrays and provide OnlySynchronizedArgument, NotSynchronizedArgument, OnlyNullArgument, NotNullArgument annotations, and perhaps something more unusual, NumberBoundedArgument, along with the matching Any, All and None combinations.

Just like all the annotations named above, NumberBoundedArgument lets you specify the index of the argument you want checked, and then it lets you select several modes:

  • LESS, i.e. arg < bound
  • LESS_EQ, i.e. arg <= bound
  • GREATER, i.e. arg > bound
  • GREATER_EQ, i.e. arg >= bound
  • IN, i.e. (arg > bound) && (arg < upperBound)
  • IN_EQ, i.e. (arg >= bound) && (arg <= upperBound)
  • OUT, i.e. (arg < bound) || (arg > upperBound)
  • OUT_EQ, i.e. (arg <= bound) || (arg >= upperBound)

where arg is the argument being compared, bound is one of the bounds (either the upper bound for LESS, LESS\_EQ, IN, and IN\_EQ; or upper bound for GREATER and GREATER\_EQ), and upperBound is the upper bound for IN, IN\_EQ, GREATER and GREATER\_EQ.

I decided to use bound both as upper and lower bound for those annotations that only use one bound as that was less confusing. Otherwise, I'd have to remember whether I set ubound or lbound for LESS.

I have also finished XML importing and exporting so that it supports passing arguments, and I fixed a bug that didn't properly join predicate annotations if the invariant was repeated several times.

I also improved violation reporting: If method arguments are passed, then the actual values will also appear in the violation log.

Consider the following nice program that uses NumberBoundedArgument:

package sample.threadCheck.predicate;
import edu.rice.cs.cunit.threadCheck.predicates.NumberBoundedArgument;
public class TCSample17 {
public static void main(String[] args) {
TCSample17 o = new TCSample17();
System.out.println("main!");
o.succeeds();
o.fails();
System.out.println("end main!");
}

void succeeds() { // these invariants all succeed
lt(0); ltEq(0);
gt(0); gtEq(0);
in(0); inEx(0);
out(0); outEx(3);
}

void fails() { // these invariants all fail
lt(2); ltEq(2);
gt(-1); gtEq(-2);
in(1); inEx(1);
out(2); outEx(0);
}

@NumberBoundedArgument(
mode=NumberBoundedArgument.Mode.LESS,
index = 0, bound = 1)
void lt(int i) {
System.out.println("lt, i = "+i);
}

@NumberBoundedArgument(
mode=NumberBoundedArgument.Mode.LESS\_EQ,
index = 0, bound = 0)
void ltEq(int i) {
System.out.println("ltEq, i = "+i);
}

@NumberBoundedArgument(mode=NumberBoundedArgument.Mode.GREATER,
index = 0,
bound = -1)
void gt(int i) {
System.out.println("gt, i = "+i);
}

@NumberBoundedArgument(
mode=NumberBoundedArgument.Mode.GREATER\_EQ,
index = 0, bound = 0)
void gtEq(int i) {
System.out.println("gtEq, i = "+i);
}

@NumberBoundedArgument(
mode=NumberBoundedArgument.Mode.IN\_EQ,
index = 0, bound = 0, upperBound = 0)
void in(int i) {
System.out.println("in, i = "+i);
}

@NumberBoundedArgument(
mode=NumberBoundedArgument.Mode.IN,
index = 0, bound = -1, upperBound = 1)
void inEx(int i) {
System.out.println("inEx, i = "+i);
}

@NumberBoundedArgument(
mode=NumberBoundedArgument.Mode.OUT\_EQ,
index = 0, bound = 1, upperBound = 3)
void out(int i) {
System.out.println("out, i = "+i);
}

@NumberBoundedArgument(mode=NumberBoundedArgument.Mode.OUT,
index = 0, bound = 0, upperBound = 2)
void outEx(int i) {
System.out.println("outEx, i = "+i);
}
}

When executed, it produces the following log file:

========================================
Log opened 2007-03-05, 02:44:17 CST (GMT-5)
----------------------------------------
Thread Predicate Violation: (9 checks, 1 violation)
	Current thread 'main', id 1, group 'main'
	Violated predicate @edu.rice.cs.cunit.threadCheck.predicates.NumberBoundedArgument
	Method arguments
		'2' : java.lang.Integer
	at sample.threadCheck.predicate.TCSample17.lt (TCSample17.java:43)
	at sample.threadCheck.predicate.TCSample17.fails (TCSample17.java:31)
	at sample.threadCheck.predicate.TCSample17.main (TCSample17.java:13)
----------------------------------------
Thread Predicate Violation: (10 checks, 2 violations)
	Current thread 'main', id 1, group 'main'
	Violated predicate @edu.rice.cs.cunit.threadCheck.predicates.NumberBoundedArgument
	Method arguments
		'2' : java.lang.Integer
	at sample.threadCheck.predicate.TCSample17.ltEq (TCSample17.java:48)
	at sample.threadCheck.predicate.TCSample17.fails (TCSample17.java:32)
	at sample.threadCheck.predicate.TCSample17.main (TCSample17.java:13)
----------------------------------------
Thread Predicate Violation: (11 checks, 3 violations)
	Current thread 'main', id 1, group 'main'
	Violated predicate @edu.rice.cs.cunit.threadCheck.predicates.NumberBoundedArgument
	Method arguments
		'-1' : java.lang.Integer
	at sample.threadCheck.predicate.TCSample17.gt (TCSample17.java:53)
	at sample.threadCheck.predicate.TCSample17.fails (TCSample17.java:33)
	at sample.threadCheck.predicate.TCSample17.main (TCSample17.java:13)
----------------------------------------
Thread Predicate Violation: (12 checks, 4 violations)
	Current thread 'main', id 1, group 'main'
	Violated predicate @edu.rice.cs.cunit.threadCheck.predicates.NumberBoundedArgument
	Method arguments
		'-2' : java.lang.Integer
	at sample.threadCheck.predicate.TCSample17.gtEq (TCSample17.java:58)
	at sample.threadCheck.predicate.TCSample17.fails (TCSample17.java:34)
	at sample.threadCheck.predicate.TCSample17.main (TCSample17.java:13)
----------------------------------------
Thread Predicate Violation: (13 checks, 5 violations)
	Current thread 'main', id 1, group 'main'
	Violated predicate @edu.rice.cs.cunit.threadCheck.predicates.NumberBoundedArgument
	Method arguments
		'1' : java.lang.Integer
	at sample.threadCheck.predicate.TCSample17.in (TCSample17.java:63)
	at sample.threadCheck.predicate.TCSample17.fails (TCSample17.java:35)
	at sample.threadCheck.predicate.TCSample17.main (TCSample17.java:13)
----------------------------------------
Thread Predicate Violation: (14 checks, 6 violations)
	Current thread 'main', id 1, group 'main'
	Violated predicate @edu.rice.cs.cunit.threadCheck.predicates.NumberBoundedArgument
	Method arguments
		'1' : java.lang.Integer
	at sample.threadCheck.predicate.TCSample17.inEx (TCSample17.java:68)
	at sample.threadCheck.predicate.TCSample17.fails (TCSample17.java:36)
	at sample.threadCheck.predicate.TCSample17.main (TCSample17.java:13)
----------------------------------------
Thread Predicate Violation: (15 checks, 7 violations)
	Current thread 'main', id 1, group 'main'
	Violated predicate @edu.rice.cs.cunit.threadCheck.predicates.NumberBoundedArgument
	Method arguments
		'2' : java.lang.Integer
	at sample.threadCheck.predicate.TCSample17.out (TCSample17.java:73)
	at sample.threadCheck.predicate.TCSample17.fails (TCSample17.java:37)
	at sample.threadCheck.predicate.TCSample17.main (TCSample17.java:13)
----------------------------------------
Thread Predicate Violation: (16 checks, 8 violations)
	Current thread 'main', id 1, group 'main'
	Violated predicate @edu.rice.cs.cunit.threadCheck.predicates.NumberBoundedArgument
	Method arguments
		'0' : java.lang.Integer
	at sample.threadCheck.predicate.TCSample17.outEx (TCSample17.java:78)
	at sample.threadCheck.predicate.TCSample17.fails (TCSample17.java:38)
	at sample.threadCheck.predicate.TCSample17.main (TCSample17.java:13)

This is a lot more informative than it used to be.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Gigabit Ethernet Experiments

Today I got the Gigabit Ethernet equipment I ordered: A Netgear GS605 5-port switch a Linksys LKG-6100 networking card for “vector” (both “scalar” and “manifold” are already Gigabit Ethernet-ready), and some new Cat 6 cables too, because the cables I used were way too long. They were from my dorm days when the Ethernet port was somewhere far away.

I took out the Siemens 5-port switch and replaced it with the Netgear one. I removed the old SMC 100 Mbit card from “vector” and put the Linksys card in. I replaced all the long, old, twisted Cat 5 cables with nice, new Cat 6 cables, and connected the Netgear switch to my DSL router. And it seemed to work! All computers were reporting 1000 Mbit network connections.

However, when I tried to copy some large files between the “scalar” and “vector”, it seemed like the transmission was happening at only 1 Mbit. That was a little slow. I also couldn’t connect to the web server on “vector”.

After a while, I figured out that the web server problem was just the DSL router firewall. Since I had changed network cards, I needed to reconfigure the firewall. And the slow transmission was due to a huge number of hardware interrupts on “vector”, probably caused by the primary hard drive, a 120 GB Maxtor (not the one that was failing yesterday; that was the 80 GB Maxtor), was running in PIO mode instead of DMA (@Update: Using this neat registry hack, I was able to revert the 120 GB Maxtor to DMA mode.@). When I transferred from a hard drive that was running in DMA mode, or when I was copying between “scalar” and “manifold”, I got the transmission rate I expected.

So, I think my Gigabit Ethernet setup works, my primary hard drive on “vector” just blows. Maybe I’ll have to replace it. Or considering that I had the other Maxtor crap out yesterday, I should replace both of them with one drive, e.g. a Seagate Barracuda 7200.10 250GB for $65 plus shipping and tax.

So… New hard drive? NAS? Both? (@Update: Because both Maxtors started to flake out — the 80 GB one disappeared completely, even though the cables are brand new and rounded, and the 120 GB one was extremely slow — I’ve decided to buy a 250 GB Seagate for $55 after S/H and tax. It’ll replace both Maxtors, and the 120 GB Maxtor will go into a mobile rack, either by replacing the current 20 GB drive in it, or by getting another rack for $10. Or I could get two new racks and then have a 160 GB, a 120 GB, an 80 GB and a 20 GB hard drive in mobile racks… But what good is that if I can’t rely on the 120 GB and the 80 GB drives? The reliability was the reason I bought the new Seagate drive.@)

Share
Posted in Uncategorized | Leave a comment

Print This Post Print This Post  

Another Hard Drive Dead

Around 2 PM today, I got a blue screen on “vector”, my web/media/SSH/everything-else server. That was unusual. I haven’t seen a blue screen in months, probably not since I last had problems with my main workstation in January.

I rebooted and noticed Apache wasn’t running. I tried to manually start the service, but it “terminated abruptly”. I read the errors logs. I ran Apache from the command line. Nothing. I looked online for help on running Apache on Windows and found an explanation that kept referring to an executable named apache, which I didn’t have (mine was named httpd). In general, the document made Apache 2.2.4 seem a lot smoother than Apache 2.2.2, which I had been running, so I decided to uninstall Apache 2.2.2 and then install 2.2.4. Then I’d merge the httpd.conf files. That should fix Apache not running, right?

Well, the install went smoothly and Apache happily displayed it’s “It works!” webpage. Then I merged my changes into the httpd.conf files, and suddenly Apache wasn’t starting anymore. I undid my httpd.conf changes, and it was starting again. I looked through the changes, and they all looked innocuous: A few default permissions, the list of files that should be treated as text, and the document root.

The document root! My D:\ (VECTOR_MISC) drive had disappeared! I rebooted several times, tried an auto-detect in the BIOS, and it still hasn’t come back. I haven’t actually opened the case yet to examine the hard drive (maybe I should have done that first), I wanted to restore a working computer first, which meant changing drive letters and the document root.

The drive that has apparently died contained my web server’s document and nothing else. I also have a DVD backup from January 24. The local copy on the MacBook might even be a bit more recent. Probably not that much has changed since then, but the largest portion of the documents are web sites and bits of knowledge that I find online and then mirror so I have local access, and I don’t know what I have added to that collection.

I don’t think my backup habits are terrible: I keep my most important files in a small Perforce server with just one user, and the files are then checked out to the machine I’m working on, so a catastrophic data loss is unlikely here. I also I make a backup of my working data on “scalar” to a separate hard drive on the same machine twice a week. Once weekly I back up my working data from the MacBook to “scalar”. Every once in a while, I make backups of all the other things, and then copy them to USB hard drives or DVDs. I keep the DVDs and the USB hard drives in a water- and fire-proof safe and duplicates of the DVDs in my bank’s safe deposit box.

I really need to automate backing up the Perforce repository, though, and I also need to automate backing up the web server’s data. And now that I’m switching to Gigabit Ethernet, perhaps I should be thinking about about a network-attached RAID storage device.

I’m still in the process of restoring the web documents. Once that’s done I can examine the hardware damage. This is still a very shitty situation. I hate administrative tasks like this.

Update

When I opened up the case and tugged a bit on the cables, the hard drive came back to life. So it seems like I’ll at least have no data loss, but I don’t know how much I can trust that hard drive anymore. It’s an 80 GB Maxtor, by the way. I have a 160 GB Seagate and a 120 GB Maxtor hard drive left in “vector” which is quite enough.

If I were to buy a replacement hard drive. I could either get a few hundred gigs PATA for about $100, or I could get a 2×250 GB RAID 1 Gigabit Ethernet device for about $300 or a 4×250 GB RAID 5 Gigabit Ethernet and Wireless LAN 802.11b/g device for about $640… but I’d rather not spend that much.

Share
Posted in Uncategorized | Leave a comment

Print This Post Print This Post  

Thanks, AT&T

On April 1, AT&T played a cruel joke on me. Exactly when I wanted to call my mom, when she had — for the first time in months — requested that I call her, my phone service went down, and I couldn’t make or receive calls. The DSL was still up, though, so at least I could tell my mom that I was trying to call her.

AT&T’s self-help instructions included a step that involved removing the DSL modem to plug in a phone directly into the outlet. I even used the oldest phone I could find, one that draws power from the phone line. Of course, the only result was that my phone service AND my DSL were down now.

When the self-help guide didn’t fix things, I filed a complaint online. AT&T’s response was:

Thank you for using AT&T Online Repair. The repair system is temporarily unavailable. Please try again later, or contact the Repair Center at one of the numbers below for further assistance. We apologize for any inconvenience. Residence Repair Center: 1-800-246-8464.

What exactly was my problem again? OH RIGHT, I CAN’T MAKE ANY DARN CALLS.

Fortunately, a friendly neighbor let me use his cellphone to make the local call to my calling card, so my mom and I managed to have a brief conversation.

I guess now that I got up at noon, after three hours of sleep, it’s back to work. I also have movie tickets for tonight. I need to arrange a time… without using the phone. It feels like a game of “The Incredible Machine”.

Share
Posted in Ramblings, Uncategorized | Leave a comment

Print This Post Print This Post  

Object Arrays for Argument Passing

Ok, during the last day and a bit, I changed my completely working implementation of passing method arguments. Before, there was one argument in the predicate method for each argument in the method that was annotated. That limited the applicability of the annotations. Now I pass an Object[] array that can be empty, contain one element, or however many. The coolest thing is that it automatically takes care of the subtyping problem.

Here are rewritten predicates and annotations from the last post:

public class TCSample14 {
public static class CheckSynchronized {
public static boolean check(
Object thisObject, Object args[], int value) {
if (value>=args.length) return false;
return ThreadCheckPredicates.checkMonitorOwned(args[value]);
}
public static boolean checkNot(
Object thisObject, Object args[], int value) {
if (value>=args.length) return false;
return !ThreadCheckPredicates.checkMonitorOwned(args[value]);
}
}

@PredicateLink(
value=CheckSynchronized.class,
arguments=true)
public static interface OnlySynchronized {
int value() default 0;
}

@PredicateLink(
value=CheckSynchronized.class,
method="checkNot",
arguments=true)
public static interface NotSynchronized {
int value() default 0;
}

public static void main(String[] args) {
TCSample14 o = new TCSample14();
System.out.println("main!");
o.succeeds();
o.fails();
System.out.println("end main!");
}

// these invariants all succeed
void succeeds() {
String o1 = "foo";
String o2 = "bar";
notUnary(o1);
synchronized(o1) {
unary(o1);
binary1st(o1,o2);
notBinary2nd(o1,o2);
}
synchronized(o2) {
notBinary1st(o1,o2);
binary2nd(o1,o2);
}
}

@OnlySynchronized(0)
void unary(Object o1) {
System.out.println("unary!");
}

@OnlySynchronized(0)
void binary1st(Object o1, Object o2) {
System.out.println("binary1st");
}

@OnlySynchronized(1)
void binary2nd(Object o1, Object o2) {
System.out.println("binary2nd");
}

// these invariants all fail
private void fails() {
String o1 = "foo";
String o2 = "bar";
unary(o1);
synchronized(o1) {
notUnary(o1);
notBinary1st(o1,o2);
binary2nd(o1,o2);
}
synchronized(o2) {
binary1st(o1,o2);
notBinary2nd(o1,o2);
}
}

@NotSynchronized(0)
void notUnary(Object o1) {
System.out.println("notUnary!");
}

@NotSynchronized(0)
void notBinary1st(Object o1, Object o2) {
System.out.println("notBinary1st");
}

@NotSynchronized(1)
void notBinary2nd(Object o1, Object o2) {
System.out.println("notBinary2nd");
}
}

Now I think this is pretty cool. It even auto-boxes primitive types to their boxed types. Now I’m just running some more tests, and then it’s time to sleep.

PS: Whatever happened to Beer Bike today?

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Do It Right the First Time

When I tried to extend the arguments=true capabilities to XML files, I ran into a small problem: All I wanted to save was “true” or “false”, but what I needed was the method signature. I didn’t want to put that into the XML file.

So I decided to change my — by now beautifully working engine — again and pass an Object array. That means the array has to be created and populated, and primitives have to be beoxed, but at leaast that way an annotation applies to a method regardless of its numbers and types of parameters.

Once I’m done with this, a simple “true” or “false” in the XML file should suffice.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Unit Tests Fail

I just noticed that ThreadCheckPredicateCheckTest fails at and after changelist 892, but succeeds at and before changelist 891, so I’ll be looking at the changes I made. Now I need to get ready for the noon seminar.

Update

The problem had to do with the numbering of auto-generated parameter names when arguments are not passed.

Of course, once you’ve found the cause of an error, it’s too tempting not to fix it, so I did fix it before I biked to Rice, and I was 10 minutes late to the seminar. Just in time ;)

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Difficult Code

My goodness, I had already forgotten how complicated the code to insert calls to predicates and especially the code to auto-generate @Combine-style predicate methods is! I got the part for the @PredicateLink almost immediately right last night already, but the code for auto-generating methods and then calling them was much harder to deal with. I think I got it now.

In both cases, the first argument passed is still this, or null in case of a static method. If method arguments are to be passed, i.e. if the @PredicateLink or @Combine annotation specified arguments=true, then the arguments follow in the exact same order as in the method annotated. This, of course, limits the applicability of an annotation. After that, the values of the annotation are passed, as before.

The biggest problem, or at least the one that took me the longest to figure out, was that I needed to generate variable names for method arguments that were passed to auto-generated predicate methods. I already do that for the variables that contain the annotation values, but I at first didn’t realize I had to do the same for the method arguments. I picked a name pattern that guarantees that the method names don’t class with the flattened annotation values: Since each method will have the arguments only at the beginning, after the this0 value, I just named them arg$$$$0, arg$$$$1, etc. Four $ aren’t in use for argument names yet.

Now I can write predicates that compare argument values or check if an arguments lock has been acquired:

public class TCSample14 {
public static class CheckSynchronized {
public static boolean checkUnaryFirst(
Object thisObject, Object o1) {
return ThreadCheckPredicates.checkMonitorOwned(o1);
}
public static boolean checkBinaryFirst(
Object thisObject, Object o1, Object o2) {
return ThreadCheckPredicates.checkMonitorOwned(o1);
}
public static boolean checkBinarySecond(
Object thisObject, Object o1, Object o2) {
return ThreadCheckPredicates.checkMonitorOwned(o2);
}
}

public static interface OnlySynchronized {
@PredicateLink(
value=CheckSynchronized.class,
method="checkUnaryFirst",
arguments=true)
public static @interface Unary { }

@PredicateLink(
value=CheckSynchronized.class,
method="checkBinaryFirst",
arguments=true)
public static @interface Binary1st { }

@PredicateLink(
value=CheckSynchronized.class,
method="checkBinarySecond",
arguments=true)
public static @interface Binary2nd { }
}

public static interface NotSynchronized {
@Combine(
value=Combine.Mode.NOT,
arguments=true)
public static @interface Unary {
OnlySynchronized.Unary value()
default @OnlySynchronized.Unary;
}

@Combine(
value=Combine.Mode.NOT,
arguments=true)
public static @interface Binary1st {
OnlySynchronized.Binary1st value()
default @OnlySynchronized.Binary1st;
}

@Combine(
value=Combine.Mode.NOT,
arguments=true)
public static @interface Binary2nd {
OnlySynchronized.Binary2nd value()
default @OnlySynchronized.Binary2nd;
}
}
// ...

This code above defines predicate methods for unary and binary methods accepting Object parameters and then checks if the first or second argument’s lock has been acquired. Annotations have been defined to check that or the opposite. Below, the class is continued with usage examples:

// ...
public static void main(String[] args) {
TCSample14 o = new TCSample14();
System.out.println("main!");
o.succeeds();
o.fails();
System.out.println("end main!");
}

// these invariants all succeed
void succeeds() {
String o1 = "foo";
String o2 = "bar";
notUnary(o1);
synchronized(o1) {
unary(o1);
binary1st(o1,o2);
notBinary2nd(o1,o2);
}
synchronized(o2) {
notBinary1st(o1,o2);
binary2nd(o1,o2);
}
}

@OnlySynchronized.Unary
void unary(Object o1) {
System.out.println("unary!");
}

@OnlySynchronized.Binary1st
void binary1st(Object o1, Object o2) {
System.out.println("binary1st");
}

@OnlySynchronized.Binary2nd
void binary2nd(Object o1, Object o2) {
System.out.println("binary2nd");
}

// these invariants all fail
private void fails() {
String o1 = "foo";
String o2 = "bar";
unary(o1);
synchronized(o1) {
notUnary(o1);
notBinary1st(o1,o2);
binary2nd(o1,o2);
}
synchronized(o2) {
binary1st(o1,o2);
notBinary2nd(o1,o2);
}
}

@NotSynchronized.Unary
void notUnary(Object o1) {
System.out.println("notUnary!");
}

@NotSynchronized.Binary1st
void notBinary1st(Object o1, Object o2) {
System.out.println("notBinary1st");
}

@NotSynchronized.Binary2nd
void notBinary2nd(Object o1, Object o2) {
System.out.println("notBinary2nd");
}
}

Now, one of the big problems, of course, is still that no method invocation conversion is performed, i.e. I can’t apply these annotations to methods that have one or two String parameters, even though String is a subclass of Object and could therefore be widened. Another problem is that right now, I have to fix the number of parameters.

Perhaps using an array of Object would be a good idea nonetheless: The predicate could call arr.length on the array and arr[i].getClass() to determine the class. Of course, I would have to auto-box primitive types. This has two disadvantages: The distinction between primitive types and their boxed versions would be lost, and it creates unnecessary objects. The advantage would be a very nice, clean way to write these annotations above:

public class TCSample14 {
public static class CheckSynchronizedArg {
public static boolean check(
Object[] args, short index) {
return ThreadCheckPredicates.checkMonitorOwned(args[index]);
}
public static boolean checkNot(
Object[] args, short index) {
return !ThreadCheckPredicates.checkMonitorOwned(args[index]);
}
}

@PredicateLink(
value=CheckSynchronizedArg.class,
arguments=true)
public static @interface OnlySynchronized {
short value() default 0;
}

@PredicateLink(
value=CheckSynchronizedArg.class,
method="checkNot",
arguments=true)
public static @interface NotSynchronized {
short value() default 0;
}

Written this way, by default @OnlySynchronized and @NotSynchronized check whether the lock of the first argument has been acquired or not, and @OnlySynchronized(2) and @NotSynchronized(2) do the same for the second argument.

But even without the array, I already think this is very, very cool, especially since it partially alleviates the need for local variable annotations: If I want to check some kind of invariant for a local variable (or argument, or field), I can just write an empty dummy method that takes the variable as parameter, and then annotate the dummy method:

public class TCSample15 {
public static class CheckNonNull {
public static boolean check(
Object thisObject, Object o1) {
return o1!=null;
}
}

@PredicateLink(
value=CheckNonNull.class,
arguments=true)
public static @interface NonNull { }

@NonNull
private static void dummy(Object o1) { }

public static void main(String[] args) {
System.out.println("main!");
String s = "foo"; // local variable
dummy(s); // check invariant
s = null;
dummy(s);
System.out.println("end main!");
}
}

Here I define a predicate that checks if the first argument is non-null. Then I create a @NonNull annotation and a dummy method that is annotated with it. Now I can check if the local variable s meets that invariant or not. The first check will succeed, the second will fail.

What else do I have on my “to do” list, besides writing the thesis, which I so elegantly postponed again by two days?

  • Allowing the arguments=true feature in XML files (@Update: Done. Import and export works now.@)
  • Checking that member annotations of @Combine-style annotations cannot have arguments=true if the combining annotation doesn’t have it set. (@Update: Done. Also checked that it’s ok to have it set in the outer annotation, but not in the inner.@)
  • @SuppressSubtypingWarning
  • Method invocation conversion (@Update: Done, kind of, because I converted to an array of Object.@)
  • More tests with DrJava
  • I also noticed that some of my unit tests are breaking now… (@Update: Done.@)

I’ll probably tackle the first item. I don’t know about the rest. Now it’s 12:45 AM, I’ve been coding for half a day again, and I haven’t gone grocery shopping. By now I think it’s time to forgo getting more bread and Gatorade and get some shuteye instead.

Share
Posted in Concurrent Unit Testing, MS Thesis | Leave a comment

Print This Post Print This Post  

Fortune Cookie

My girlfriend just got delicious Chinese take-out food for us, and after dinner, I read my fortune cookie. It said:

Failure is feedback. And feedback is the breakfast of champions.

I never considered myself a breakfast person, so either I’m wrong about that or I don’t fail that often. Coincidentally, though, failure really is the only feedback in concurrent testing right now. If something goes wrong, you know there’s an error. If a concurrent unit test passes, you don’t know very much.

Before dinner, I’ve been fixing a few bugs that were left in yesterday’s implementation of passing method arguments. One bug was particularly confusing, and I stared at disassembled Java code for about an hour. I finally realized that I was using a HashMap to store the parameter types, and the order of the keys isn’t fixed, so I was getting randomized method signatures.

Now I’m tinkering with @Combine-style annotations and passing method arguments.

Share
Posted in Concurrent Unit Testing, Ramblings | Leave a comment

Print This Post Print This Post  

More Limitations

I was just going to look at how to make the arguments=true facility accessible to XML files, but so far I haven’t been able to figure it out. It seems so easy, just add a property to the node: <predicate arguments="true">. Unfortunately, the XML only contains the definition of the predicate, but what I really need here is the signature of the method the predicate will be applied to, i.e. something like “IILjava/lang/String;”.

So I decided to ignore that issue for a while and focus on the other things that need to be done:

  • @Combine-style annotations
  • reflection-based code
  • accept a predicate method if the classes of the arguments are all superclasses of the classes actually passed

That’s when I noticed another limitation: I don’t think I can pass arguments for the reflection-based Thread Checker. At least not easily. The reflection-based Thread Checker has one method, and it gets called with the class and method name of the predicate it is supposed to invoke. If I were to pass the method’s arguments, then that method would have to have an arbitrary number of signatures. Of course I could use an array of Object, but then I’d have to convert primitive types to objects, so I decided to ditch that issue for now, too. (@Update: Now that I am passing an array of Object, of course I can support reflection.@)

As for allowing superclasses in the predicate method: Am I going to implement full-blown Java method invocation conversion? Ugh.

To quote the JLS, from 5.3 Method Invocation Conversion:

Method invocation conversion is applied to each argument value in a method or constructor invocation (§8.8.7.1, §15.9, §15.12): the type of the argument expression must be converted to the type of the corresponding parameter. Method invocation contexts allow the use of one of the following:

  • an identity conversion (§5.1.1)
  • a widening primitive conversion (§5.1.2)
  • a widening reference conversion (§5.1.5)
  • a boxing conversion (§5.1.7) optionally followed by widening reference conversion
  • an unboxing conversion (§5.1.8) optionally followed by a widening primitive conversion.

If, after the conversions listed above have been applied, the resulting type is a raw type (§4.8), an unchecked conversion (§5.1.9) may then be applied. It is a compile time error if the chain of conversions contains two parameterized types that are not not in the subtype relation.

If the type of an argument expression is either float or double, then value set conversion (§5.1.13) is applied after the type conversion:

  • If an argument value of type float is an element of the float-extended-exponent value set, then the implementation must map the value to the nearest element of the float value set. This conversion may result in overflow or underflow.
  • If an argument value of type double is an element of the double-extended-exponent value set, then the implementation must map the value to the nearest element of the double value set. This conversion may result in overflow or underflow.

If, after the type conversions above have been applied, the resulting value is an object which is not an instance of a subclass or subinterface of the erasure of the corresponding formal parameter type, then a ClassCastException is thrown.

From 8.4.8.3 Requirements in Overriding and Hiding:

It is a compile time error if a type declaration T has a member method m1 and there exists a method m2 declared in T or a supertype of T such that all of the following conditions hold:

  • m1 and m2 have the same name.
  • m2 is accessible from T.
  • The signature of m1 is not a subsignature (§8.4.2) of the signature of m2.
  • m1 or some method m1 overrides (directly or indirectly) has the same erasure as m2 or some method m2 overrides (directly or indirectly).

And from 8.4.2 Method Signature:

It is a compile-time error to declare two methods with override-equivalent signatures (defined below) in a class.

Two methods have the same signature if they have the same name and argument types.

Two method or constructor declarations M and N have the same argument types if all of the following conditions hold:

  • They have the same number of formal parameters (possibly zero)
  • They have the same number of type parameters (possibly zero)
  • Let be the formal type parameters of M and let be the formal type parameters of N. After renaming each occurrence of a Bi in N’s type to Ai the bounds of corresponding type variables and the argument types of M and N are the same.

The signature of a method m1 is a subsignature of the signature of a method m2 if either

  • m2 has the same signature as m1, or
  • the signature of m1 is the same as the erasure of the signature of m2.
Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Doing More Exciting

Of course, doing something is more exciting than writing about it, so after I stopped writing about my idea to pass method arguments last night, I started looking at the code. Last night I wasn’t able to make much progress, but today I implemented the feature for standard @PredicateLink-style annotations.

I accomplished it by adding a arguments value to the @PredicateLink annotation: By default, it’s set to false, but if it is set to true, then the method arguments will be passed after the value of this (or null in case of a static method), but before the values of the annotation.

This is a very cool feature, as it allows me to write predicates like the one I desperately needed in one of my examples, namely that the two arguments are distinct objects. However, the downside, of course, is that it ties an annotation to a particular signature of a method, making annotations much less universal. It gives the programmer the power to write annotations for specific methods, though, and this at least partially removes the necessity of having annotations for local variables to express invariants for them.

Here’s an example of something I can write now:

public class TCSample12 {
public static class CheckIdentity {
public static boolean check(
Object thisObject, Object o1, Object o2, boolean same) {
return same?(o1==o2):(o1!=o2);
}
}

// calls TCSample12.CheckIdentity.check
// (Object thisObject, Object o1, Object o2, boolean same)
@PredicateLink(value=CheckIdentity.class, arguments=true)
@interface TestIdentity {
boolean same() default true;
}

public static void main(String[] args) {
TCSample12 o = new TCSample12();
System.out.println("main!");
String s = "foo";
String t = "bar";
o.distinct(s, t);
o.same(s, s);
System.out.println("end main!");
}

@TestIdentity(same = false)
public void distinct(Object s, Object t) {
System.out.println("distinct! s = '"+s+"', t = '"+t+"'");
}

@TestIdentity
public void same(Object s, Object t) {
System.out.println("same! s = '"+s+"', t = '"+t+"'");
}

For the same method, the invariant is that both arguments have to be identical; for the distinct method, it’s that both arguments have to be distinct. I have direct access to the method arguments. Pretty cool, huh?

One problem that I still have is that the predicates don’t support any kind of subtyping. The methods same and distinct use Object, and so does the predicate method CheckIdentity.check. If, however, the methods used String, a subclass of Object, and the predicate method still used Object, the Thread Checker would find no match. I don’t think this will be too hard to solve, though.

I also haven’t fixed up @Combine-style annotations. There are a few difficulties here: First of all, even if a @Combine-style annotation specifies arguments = true, it is up to the member annotation whether the arguments should actually be passed. So I have to decide this on a case-by-case basis. It will also make loading the arguments onto the stack a bit more difficult, since the method arguments are at the beginning of the array of local variables, so I can’t just linearly iterate over the array anymore, but that’s not too hard to solve either.

Second, if a @Combine-style annotation does not specify arguments = true, then none of its member annotations can do that either. Where would that information come from? An additional check is needed here.

Third, I don’t expose this ability in external XML files yet.

I haven’t even touched the @SuppressSubtypingWarning annotation, but I think that really does have low priority for me. This was more important, because I plan to stick with the same small set of examples for the entire thesis, and if I can’t satisfactorily fix one of them, then it will seem like there’s a gap in my work.

Share
Posted in Concurrent Unit Testing, MS Thesis | Leave a comment

Print This Post Print This Post  

More Annotations Needed

When I was writing simple Java examples that may be problematic, even with Thread Checker annotations in place, I noticed two annotations that were still missing.

The general problem I was describing is a result of subclassing: If a method of a superclass A was written one way, there is no guarantee that a subclass B extends A doesn’t change the behavior. Or, more indirectly, an instance of a subclass may be passed as a parameter, which could alter the behavior of a method call to it.

For the second case, it is very difficult to write predicate annotations right now, because there’s no direct access to method arguments. I guess I could change the link between annotations and predicates and not only pass this as first parameter, but pass all other arguments as well. That probably wouldn’t be very difficult to implement, but it would limit an annotation to a particular method signature. Perhaps I could specify which, if any, arguments should be passed… I’ll have to mull this over. Right now, this doesn’t have very high priority for me.

Another annotation that may be useful would be an @SuppressSubtypingWarning annotation. In some cases, for example when implementing Runnable.run or overriding Object.toString, it may be useful to specify invariants without getting the static subtyping warnings that would normally be generated, since both methods are first introduced higher up in the hierarchy without invariants. But again, this doesn’t have very high priority right now. For now, I’ll just require programmers to manually ignore the warnings.

What is a little disappointing is the realization that these two problems can only be avoided if programmers consistently annotate their concurrency invariants. If a method makes a call to an unannotated, carelessly written method, or an annotated class is extended but the invariants not correctly adapted, all bets are off.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Concutest Community Project

Some time this morning, after seeing the results of the conversion to concurrency definition-based XML files, I had the idea of trying to turn the project to gather all information about Java’s concurrency invariants into a community effort.

I first thought I’d create a database, but then I decided I’d use what I know best: A WordPress blog. So now I’m hosting another blog, called the Concutest Community Project at http://community.concutest.org/

The idea is that anyone can register and write posts describing concurrency invariants. The posts can be sorted into categories based on the kind of invariants and the package the class is in. Other people can comment on the validity of the posts or use a 5-star gadget to rate the quality, and every once in a while, I’ll go through the posts, verify the information, and generate a new version of the Java API database.

Since the information is categorized by invariant and package, it’s also easier to browse and find concurrency invariants for classes a developer uses.

We’ll see how it goes.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Time Magazine

In the last two weeks, I’ve been so sick and slept most of the time, or at most read through my comments and digitized them, that I hardly got anything done. During the last three days, when I started to feel better, I’ve had mad 8 to 10 hour coding sessions to implement the idea about how to delineate threads by invariant before I got sick. I finally got done, but the sickness and this coding project halted my work on the thesis.

In retrospect, I think the refactoring and the concurrency definitions turned out to be very smooth, smoother than I had originally intended, even though there still are some rough edges, but it’ll have to do now. It’s nice that both kinds of XML files can be handled exactly the same now, and that they all get merged, eliminating redundant checks.

During the last two weeks, I’ve really just slept, tried to stay hydrated, performed some simple tasks that didn’t need too much focusing, like upgrading my blog software to WordPress 2.1 (finally, from 1.5) and making minor fixes, done a number of backups (scalar to DVD and USB hard drive, Perforce to DVD and USB hard drive, my old quantum account to USB hard drive, and manifold to scalar’s backup partition — yes, that all took a LONG time). Now at least I got some coding done.

Anyway, I’ve done so little, I haven’t even had time to read my “Time” magazine from last weekend, even though its cover story sounds very interesting: “Where the Right Went Wrong”. I long to read it, but now the new “Time” issue has arrived, and its feature article is “Why the Bible Should Be Taught in Schools”. Another must-read. Somehow, I don’t like their new format, introduced two or three issue ago, as much anymore. It’s too hard to browse, the columns of the articles are too wide for comfortable reading, the entire magazine seems disorganized. However, I’m sure I’ll miss a magazine like “Time” once it expires, so maybe I’ll return to “Newsweek” again. For now, I’ve decided to watch a movie and then go to bed early (probably midnight or 1 AM instead of 9 AM).

So far, “James Bond 007 – Casino Royale” has been a very different Bond, and somehow rather disappointing. Sure, he’s gruff, the entire movie is gritty, but where is Bond? It probably had the most complex beginning, but then… Come on, a card game to finance terrorism? I thought terrorists would be smarter than to resort to gambling, which, after all, is a tax only to be paid by those who are bad at math. I own all Bond movies (including “Never Say Never”, which I don’t really consider legitimage) on DVD. I’m glad I only rented “Casino Royale”. Towards the end, Brosnan was hard to see (especially in his invisible car), but this… is just not Bond. I’m a faithful fan of the series, though, so I’m sure to look at Daniel Craig 007 in a few years.

The coughing isn’t as bad anymore, even though tonight it returned a bit, but at night it often gets worse. I’ve also had incredibly painful leg cramps in my lower left leg when I tried to get up Friday and Saturday morning. I think my neighbors must have suspected I got slaughtered. And the hours of straight coding made my left shoulder go numb again. The leg and should still hurt a bit, but I don’t think it should impede my ability to return to work tomorrow.

I hope I’ll be well again soon. I really miss beer — completely stayed away from alcohol — and Beer Bike is coming up. Wish me good night and good luck ;)

Share
Posted in Concurrent Unit Testing, MS Thesis, Ramblings, Uncategorized | Leave a comment

Print This Post Print This Post  

Page Not Found?

I’m getting a number of reports that users click on links and don’t get where they should be taken:

Subject: A Concurrent Affair: Bad Link to
/blog/index.php/2006/09/19/local-variable-annotations/blog/index.php/
2006/09/19/local-variable-annotations/

A user tried to go to

http://www.concurrentaffair.org/blog/index.php/2006/09/19/local-variable-annotations/
blog/index.php/2006/09/19/local-variable-annotations/

and received a 404 (page not found) error.
It wasn’t the user’s fault, so try fixing it. The user came from

http://www.concurrentaffair.org/index.php/2006/09/19/
local-variable-annotations/

It looks like something with my permalinks or mod_rewrite is wrong, but I just can’t figure out what’s going on. If anyone notices this problem, could you please post a comment and describe what you were doing, i.e. what URL was displayed in your browser, what link you clicked on, and so on?

Thanks.

Share
Posted in Uncategorized | Leave a comment

Print This Post Print This Post  

Concurrency Definitions Implemented

I just finished implementing concurrency definitions. This is an alternative view on external XML files, as explained previously: Instead of listing every class and method, and then saying what it may or may not do, concurrency definitions define a set of invariants, and then list methods and classes that must maintain those invariants.

I basically rotated the whole picture by 90 degrees, or to quote the example I used to explain the concept to my girlfriend:

Previously, I had a list of countries, and for each country, I’d say what someone does or does not do there. For example:

  • United States:
    • People drive on the right side of the road
    • People may not drink in public
    • People speak English natively
  • England
    • People don’t drive on the right side of the road
    • People may drink in public
    • People speak English natively
  • Germany
    • People drive on the right side of the road
    • People may drink in public
    • People don’t speak English natively

Note that these are all either-or properties; if someone drives on the right side of the road, then he implicitly doesn’t drive on the left side. That’s why I’ve listed some properties in italics; stating them isn’t necessary, because the opposite wasn’t said.

This is a very natural representation if you’re in a certain country and want to find out what somebody does or doesn’t do. However, if you’re compiling lists about these things, chances are it’s a whole lot easier to compile a list about driving, a list about drinking, and a list about speaking English, and then listing the countries in each category:

  • People drive on the right side of the road:
    • United States
    • Germany
  • People may drink in public:
    • England
    • Germany
  • People speak English natively:
    • United States
    • England

I claim this list is easier to compile, because you have to think about just one thing, and then go through the list countries. In the other, original approach you would enumerate the countries, and then try to list every property you can come up with.

The original approach (I describe it as class-based or <threadcheck> approach) was well-suited for instrumenting class files, because the instrumentor was basically a traveler through all the classes and methods, and what the instrumentor wanted to know was “what can I do here?” I therefore don’t regret writing it that way, and in fact, it’s still written that way. It’s just a much more efficient format.

However, when I look at the current Java API annotations, then I don’t get a clear picture of what may be done and what may not be done. I just don’t see the categories, the invariants. All I see again are classes and methods, and that brings us back to the original problem: The boundaries between classes are not the same as the boundaries between threads.

I just converted the same annotations in the XML file shown in the other poast from the old format to the new format (I call it as concurrency definition-based or <threadcheckLdef> approach), and I must say I find it significantly easier to understand:





















































































than the old XML file (reproduced here for your enjoyment):





































































































































































































In the newer version, I can clearly see the three different invariants I’m using. I had no idea what I’d been using in the old one, without actually going through it line by line.

Making this happen caused a major refactoring that touched the XML configuration library and loading external XML annotations. I factored out most common code, and now it is even possible to convert one XML representation into the other and back, and to merge them while eliminating overlap. Annotations can now also be printed out just like Java code, which helps a lot in generating human-readable output.

My MacBook has been silently working on a remote backup to my server’s backup drive for, oh, 8 hours now, and it’s only half done. I should have plugged in the Ethernet cable first.

I’m cautiously optimistic about my health. Yesterday and today I haven’t had to cough very much anymore, and there was hardly any mucus. Both times when I got up I had a horrible muscle cramp in my lower right leg, though, one that made me scream out loud (“sol”, like “lol”?). After stretching a bit, I limped into the bathroom and took a hot bath.

I also made a bunch of backups in the past days and finished a small home-improvement project: I finally connected the line-out of my media server to the stereo in my bedroom. The sound quality has improved remarkably when not only my two small computer speakers are playing. I ran the speaker wire up in the corner of the walls, along the edge of the ceiling, and then through the air conditioning duct. Most of it is hidden.

Of course, it’s not as fancy or functional as a Squeezebox, but I did this for about a tenth of the price.

It’s 9 AM now, I need to go to bed. I think I’ll let my MacBook finish its backup. Good night/morning.

Share
Posted in Concurrent Unit Testing, Uncategorized | Leave a comment

Print This Post Print This Post  

Surrounded by Morons

I really must be surrounded by morons, at least in the retail world: Let me give you two examples just from the last two weeks.

Headphones

On March 09, 2007, I placed an order with Buy.com for Creative Headphone HN-700 EF noise-cancelling headphones. My PC headphones at home finally gave up after over five years, so I took my office headphones home. Now I had headphones at home, but not at work, and at Duncan, especially in rooms with an open ceiling, it can get pretty noisy, so noise-cancelling headphones sounded like a good idea.

They were supposed to be $59.99, minus a $5 coupon, and then there’s a $30 mail-in rebate, so the final price was supposed to be $24.99. I found that acceptable, at least on the night I placed the order. On the next morning, I woke up more frugal and decided to cancel the order. I hit the “Cancel” button, but I was told the order could not be cancelled because it had already been “sent to the warehouse”, whatever that means. I was told I had the option of refusing the order (couldn’t do that, had to be at work) or pay return shipping myself. I decided it was better to keep the item. And I’m glad I did, because the noise-cancelling features work really well, music sounds crisper with it enabled, the headphones fold up into a really tiny travel bag, and there’s even a two-plug adapter for airplanes.

My headphones were not cancelled. But guess what did get cancelled? The $5 coupon! So the price for my headphones suddenly went up by $5. I have a receipt that states $54.99 as price before the rebate, but my credit card got charged $59.99. I have already submitted an electronic complaint to Buy.com (after being on hold on the phone for 25 minutes; speaker phone only gets you so far), and if I don’t get those $5 back, I will even go as far as contacting the Better Business Bureau for the Los Angeles area (try contacting a BBB if you have a problem, they’re often very helpful). I think this is absolutely unethical: I felt doubly screwed, because I couldn’t cancel an order that hadn’t even shipped yet, but the coupon that would have made the unwanted purchase cheaper was cancelled. Buy.com is so consumer-unfriendly, they don’t even have a phone number listed on their website. I had to get (877) 780-2464 from a third-party website.

At least I’m happy about the headphones; naturally, I’m not happy about having to hunt down $5, and perhaps it’s not worth it, but I believe consumers can’t let businesses get away with practices like this. LA’s BBB report shows that Buy.com appears to be a good company; this is the first time I’ve had problems with them, but there are plenty of other vendors out there, so it all depends on how I get treated when I do have a problem.

I just got an email from Buy.com, just barely outside the 24-hour window they promised, and I guess a strong action like involving the BBB won’t be necessary. Here’s the core content:

We would like to inform you that when you request for cancellation, the
system automatically cancels the coupon that is included in the order.
This happens although the item may have been shipped.

I absolutely don’t agree with the policy that cancels coupons. If I want to cancel an order, then all items that can be cancelled because they haven’t shipped yet should be cancelled. I also understand if coupons are cancelled because the remaining items don’t meet the coupon criteria, e.g. minimum price, anymore. But that wasn’t the case here at all. This is a bad policy, or probably a result of bad programming.

Please note that you can still use the $5 coupon on your next order. All
you have to do is send us an email containing the new order number once
the item is shipped. We will manually apply the coupon.

We thank you for your understanding.

Uh, you’re welcome, but you don’t have my understanding. Who says I’m ever going to buy from them again? And I have to write an email? Another one? And they are going to apply it manually? That’s supposed to work? People screw up, often even twice in a row, as the second example will show.

Office Chair

I have a very nice office chair in my home office (picture). I bought it during my second semester as an undergrad at Rice because my back just hurt. Rice has (or at least had at the time) horrible chair-desk combinations: The chairs are too low, particularly with my long legs, and the desks are too high; I don’t know, maybe I have long legs but an extremely short torso. The result was that I constantly had to pull my shoulders up, and that lead to considerable back strain.

I got a really good deal on the chair. I bought it at the local Office Depot, the brand was called “Furniture at Work”, and delivery was free and quick. It has extremely good lumbar support, pretty soft leather, a deep seat cushion, a high back rest, and padded armrests that are just right: They don’t extend too far, so I can have the seat all the way up (for my long legs) but still slide under the desk and get close to the keyboard. Now my chair is nearly six years old, and it’s showing a little bit of aging. Some screws and bolts that hold the chair together have mysteriously disappeared, and the bottom cushion has become a little flat (must be the result of my short torso pressing on it). So I’ve been looking for a replacement chair, and so far I haven’t found one. Once I actually went to a local Office Depot store with a measuring tape and measured all chairs. Either the seat wasn’t deep enough, the back rest not tall enough, or the armrests were cheap, not padded or extended too far.

On Monday, March 21, while I was sick, I noticed this chair on edealinfo.com: A Staples® Culley™ Caressoft® Manager’s Chair (picture; I made backup pictures in case Staples changes its website) for only $59.99, free delivery, or $64.94 with tax. Now, I had never seen this chair, so I didn’t know if it would work, so I called Staples on Monday. The representative said if I don’t like it, I can return it to a store or have it picked up within 14 days for a full refund.

So I ordered it. It was supposed to be delivered by Staples’ own special carrier on Tuesday, March 22, some time from 9 AM to 5 PM. I was still sick, so that wasn’t a major problem, but I really needed to get groceries. I was scared to leave my apartment, but I ended up making a 15-minute dash to Kroger to buy Gatorade to stay hydrated. I really doubt I missed the delivery, especially since there was no note. That night, the tracking website stated “Refused by Customer; REFUSED BY R”. Huh?

On Wednesday I called Staples again and explained my problem. The representative, Angela, couldn’t figure out what had happened either, so we decided to place a second order for the same item, for the same price, to be delivered today, on Thursday, March 22. There’d be two charges for the chairs, but I’d get a refund for the first chair once it gets back to the warehouse, if it does.

So today I spent the entire day waiting for that delivery again. I’m still sick, and I was tired from last night’s coding session, so it wasn’t a big deal either. The tracking website still doesn’t show a delivery, but surprisingly when I checked my mail at the apartment management, the chair had been delivered. No note, no anything. Directly to the apartment management, not to me, the customer. But at least I had the chair, or so I thought.

When I looked at the carton, though, it looked awfully small, and the SKU didn’t match. The chair that I had been delivered was a Situations Leather Task Chair, Black (picture) for a measly $39.99. Look at it! I can’t sit on something like that for a whole day.

I just made a third call to Staples and finally blew the whole thing off. I don’t want the chair anymore, even if I could still get the right one, which admittedly looked nice. I arranged with the third representative I talked to, Amanda, that someone would come and pick the thing up on Monday, March 26, for a full refund. She also threw in a $20 certificate for my ordeal. Thank you.

Now, the problem is that I won’t be at home on Monday (hopefully, unless I’m spitting blood again), so I can’t sit around the whole day and wait for the idiot driver. I’ve asked if the driver could pick it up at the apartment management’s office, and that’s definitely an option. Perhaps I’ll also take it to a Staples store, but without a car, that’s not so easy, because apparently the closest store is on the Beltway, 15 miles away (@I just found out that there are no Staples stores in Houston at all, so I guess I’ll have to leave it at the management office. Will things get even worse? Stay tuned after these messages…@), (@It’s even worse than I thought: I just called Staples again to reschedule the pickup to Tuesday when I can be at home, because I didn’t want to leave a $65 item under the responsibility of someone else (see will it get worse?) Now Renee explained to me that the pickup isn’t even guaranteed to happen on a specific day, but over a period of five days, and they’ll make three attempts. This is absolutely ridiculous.@). I’ll have to think about that. But I just can’t believe how wrong things can go…

I got another spam fax. I’m pissed off by now, so I filed a complaint with the FTC. It was the third time I got that spam fax. It’s also taking forever to make a backup. Somehow splitting the large backup file into 4 GB segments for my FAT32 external hard drive takes an eternity (@I decided to format my 120 GB Western Digital Passport USB hard drive to NTFS, that way I don’t have to split files larger than 4 GB. Now the Mac can’t read it anymore, but I had to do something similar with my 80 GB Gigabank USB hard drive already, it uses HFS+, which Windows can’t read. So now I have two dedicated external hard drives, but that doesn’t bother me too much@). I’m still coughing, though not as bad anymore; an end is not yet in sight, and my girlfriend is feeling sick too. I can pretty much work again, but I haven’t tried biking, and I just refuse to accept this as normal. This isn’t “health”.

On the other hand, I received my tax refund, and while PayPal refused, Chase agreed to give me a refund for a fraudulent eBay transaction from December. Now I just need to get all that money refunded.

Share
Posted in Ramblings, Uncategorized | Leave a comment

Print This Post Print This Post  

Partial Implementation

During the night I looked after a person who I care about a lot who seemed to have suffered from a strange drug interaction of nose spray and inhaler. He said he felt like he wasn’t himself, he felt slow, and I was really worried. I spent probably an hour and a half Googling the different medications, trying to find some interaction. My guess is that there just was a weird interaction between a vasodilator and a vasoconstrictor (@A friend in medical school confirmed this to a degree: If the nose spray actually makes it into the lungs, it could constrict blood vessels there and make an asthma attack worse.@). There was one disturbing comment about the nose spray causing severe CNS depression in children, so even when he seemed to be sleeping, I just wanted to be safe and woke him up a couple of times.

I’ve implemented most of what seems like the import code for XML concurrency definitions. I’ve also written a tool that checks the validity of the XML files, and I’ve enhanced my unit test suite for XMLConfig. I haven’t actually tested whether XML concurrency definitions get instrumented as checks, and I’m too sleepy for now. I actually feel loopy. I should probably take my cough medicine and go to bed.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Some More XML Changes

I’ve realized that, in order to maximize code-reuse, I’ll have to change the XML format for the concurrency definition again. In the past, the XML node for the annotation didn’t have any child nodes that described classes or methods; in the proposed format, the classes and methods would be the child nodes. This wouldn’t really be a problem with the example I’ve used so far, but predicate annotations are more complex, and I don’t want to mess with them. It would make it more difficult to implement, so I’m taking the easy way out and proposing the following syntax:









All I’ve done is add the invariant node, which will contain the annotation. That means the three valid child nodes for a <threadcheck:def> node are invariant, class, and method, and there needs to be at least one invariant node and at least one of the other two node types. Very simple.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Upgrade to WordPress 2.1

I finally dared to make the upgrade to WordPress 2.1. I hope that everything still works. Unrolling WordPress is an incredible pain.

Update: I had to update and patch some of the plugins, but so far, everything seems to work. On the other hand, besides the capability to export WXR (WordPress eXtended RSS) and some more optical bling like color fades and AJAX-expandable tabs, I can’t really see anything that was important in the upgrade. (@I guess autosave is worth something, if it works.@)

I really wanted the WXR, though, because it seemed to be the easiest way to import my blog into one hosted at wordpress.com, which I could then use with blurb.com to create a blog book. However, the BookSmart software is buggy, and the book looked stupid. So I gave up.

I found a cool plugin, though, that allows me to insert footnotes, as already exemplified above. I think I may use that instead or in addition to Updates in the future. And the wp-polls plugin is nice too. Maybe I’ll use it.

Share
Posted in Uncategorized | Leave a comment

Print This Post Print This Post