Using Timeslots in a Hashmap

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Using Timeslots in a Hashmap

turban
Hi I’m having a little problem with the “Timeslot” class. I’m using a HashMap to store some Timeslots (e.g. HashMap<CustomerInfo, Map<Timeslot, List<Double>>>) If I play a single game I’m not having any problems. But if I play some games in a row (with the option “--repeat-count”), I am facing the following problem.

Here is the code I am using to show the problem:
[ts and currentTimeslot are two Timeslot instances]
System.out.println("adding: " + customer + " for TS: " + ts + " usage: " + usage + " current: " + currentTimeSlot);
System.out.println("ts: " + ts.getSerialNumber() +"(" + ts.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(ts))+")" + " current: " + currentTimeSlot.getSerialNumber() +"(" + currentTimeSlot.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(currentTimeSlot))+")" + " equals: " + currentTimeSlot.equals(ts));


Game-1:
adding: CustomerInfo(freezeco-3) for TS: timeslot 371:2008-09-30T11:00:00.000Z usage: -20.340669618253948 current: timeslot 371:2008-09-30T11:00:00.000Z

ts: 371(org.powertac.common.Timeslot@43bf730) current: 371(org.powertac.common.Timeslot@43bf730) equals: true

The equals() method returns true (which is obviously correct).

Game-2:
adding: CustomerInfo(freezeco-2) for TS: timeslot 363:2008-09-30T03:00:00.000Z usage: -26.090487128139344 current: timeslot 363:2008-09-30T03:00:00.000Z

ts: 363(org.powertac.common.Timeslot@661fd075) current: 363(org.powertac.common.Timeslot@4eca6cfe) equals: false

 Here the equal method returns false (which is semantically incorrect).

In game-2 this will always be false: foo.get(customer).containsKey(currentTimeSlot). Since containsKey() tries to use the equals() method.

I think that in game two the timeslots should be equal (same serial number, and same in-game time). I think this problem should be fixed, if the equals() method would be overridden in the “Timeslot” class.

I hope you get my problem.

Greetings,
Tobias


Reply | Threaded
Open this post in threaded view
|

Re: Using Timeslots in a Hashmap

grampajohn
Administrator
turban wrote
Hi I’m having a little problem with the “Timeslot” class. ...
Tobias -

Thanks for the clear report. This is issue #761. I will try to take a look at in the next day or two.

John
Reply | Threaded
Open this post in threaded view
|

Re: Using Timeslots in a Hashmap

grampajohn
Administrator
In reply to this post by turban
Tobias and all -
turban wrote
Hi I’m having a little problem with the “Timeslot” class...
I have checked to be sure that the TimeslotRepo is cleared out at the beginning of each game. What this means is that the timeslots from game 1 are not the same as the timeslots in game 2. So if you are keeping a data structure around between games that contains timeslots (or any other data type that is stored in one of the Repos), that's actually a memory leak. Better to just use the timeslot index instead of the timeslot itself as a key.

Does this make sense, or is this not what's happening in your case?

John
Reply | Threaded
Open this post in threaded view
|

Re: Using Timeslots in a Hashmap

turban
Hi John,

I’m clearing all my DataStuctres between two games.
Do I have to call “this.timeslotRepo.recycle();” myself ?

This is the method I have trouble with: (my code)
public void addCustomerUsage(CustomerInfo customer, double usage, Timeslot ts, Timeslot currentTimeSlot) {

And this is a possible call: (- PortfolioManagerService - handleMessage(TariffStatus ts)
this.custUsagePredictor.addCustomerUsage([…], ttx.getPostedTimeslot(), this.timeslotRepo.currentTimeslot());

If I understand the documentation correctly the two timeslots should be identically. Since the currentTimslot should be the timeslot the transaction was posted.
 But in my tests they are not.

        if (!foo.containsKey(customer)) {
            foo.put(customer, new HashMap<Timeslot, List<Double>>());
        }
        if (!foo.get(customer).containsKey(ts)) {
            foo.get(customer).put(ts, new LinkedList<Double>());
        }
    if (foo.get(customer).containsKey(currentTimeSlot)) {
//This code is never reached!
 […]
}
I don’t get why the coed works fine in the first game but not in the second.
The timeslots in the Transaction and TimeslotRepo seem to differ in the second game.

Right now we are using this ugly workaround
        for (Timeslot ts1 : this.foo.get(customer).keySet()) {
            if (ts1.getSerialNumber() == currentTimeSlot.getSerialNumber()) {
which fixes the problem for now.

Also we don’t want to use the timeslot index because we need the “slotInDay”. Of cause we could compute it but that is just more overhead than the ugly workaround.

Greetings,
Tobias

Reply | Threaded
Open this post in threaded view
|

Re: Using Timeslots in a Hashmap

grampajohn
Administrator
turban wrote
I’m clearing all my DataStuctres between two games.
Do I have to call “this.timeslotRepo.recycle();” myself ?
All repos are recycled in core.PowerTacBroker.init(), line 197.

I am not quite sure where you are getting the non-eq Timeslot from if you clear all your data structures, but we have made no serious attempt to ensure that there are never two Timeslot Instances with the same index. Rather than try to chase down the problem (or convince me or someone else to chase it down), it would be far better to adopt the approach used everywhere else in the server and in the sample broker, which is to use the timeslot index as a key rather than the timeslot itself. It's an int, so there should never be a problem with equality.

Cheers -

John