Why does AsyncMap's putIfAbsent return NULL when a new object IS created?

353 views
Skip to first unread message

Kegan Holtzhausen

unread,
Mar 22, 2016, 9:15:21 AM3/22/16
to vert.x
Hi,

Why does putIfAbsent return a NULL if a new object is inserted, and only return a object if it is ALREADY present? Because I need to call it twice in order to get my map document created.

        // create the nodes object if its missing
        nodesMap.putIfAbsent("nodes", new JsonArray(), res2 -> {
          if (res2.succeeded()) {
            logger.info((res2.result()));
          } else {
            logger.warn("unable to put new nodes");
          }
        });

        // add the address of this node to the nodes object
        nodesMap.putIfAbsent("nodes", new JsonArray(), res2 -> {
          if (res2.succeeded()) {
            res2.result().add(uniqueAddress);
          } else {
            logger.warn("unable add this node to nodes");
          }
        });


I just don't understand why I can't get the "New" object back if it is created, rather than a NULL for the "first" node in the cluster.

/Kegan

Tim Fox

unread,
Mar 22, 2016, 9:26:39 AM3/22/16
to ve...@googlegroups.com
It just follows the semantics of ConcurrentMap.putIfAbsent:

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentMap.html#putIfAbsent-K-V-

Not sure what you are trying to achieve here. Could you elaborate further?
--
You received this message because you are subscribed to the Google Groups "vert.x" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vertx+un...@googlegroups.com.
Visit this group at https://groups.google.com/group/vertx.
To view this discussion on the web, visit https://groups.google.com/d/msgid/vertx/bd9ef8a7-7748-4f85-b62e-dde68bf5a6e1%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Kegan Holtzhausen

unread,
Mar 22, 2016, 9:30:57 AM3/22/16
to vert.x
Hi Tim!

I have a cluster I am "bootstrapping", and I need to create some objects in the clusterwidemap if they are NOT present. And since the callback is a null on "successful" creation of a new object in the map, I need to do a second "put" in order to actually get the resulting object so I can append data to.

/Kegan

Tim Fox

unread,
Mar 22, 2016, 9:43:39 AM3/22/16
to ve...@googlegroups.com
The normal idiom of putIfAbsent in ConcurrentMap is something like the following:

Object myObject = new Object();

Object obj = map.putIfAbsent(key, myObject);

if (obj == null) {
    obj = myObject;
}

// Now do something with obj

If two different threads concurrently executed the same code, then obj will reference the same object by the time the code completes for both threads

Similarly for the async putIfAbsent it's designed to be used something like this:

Object myObject = new Object();

map.putIfAbsent(key, myObject, res -> {
    if (res.succeeded()) {
        Object obj = res.result();
        if (obj == null) {
            obj = myObject;
        }
        // Now do something with obj
    }
});

So there's no need to do a second put.

Kegan Holtzhausen

unread,
Mar 22, 2016, 10:16:10 AM3/22/16
to vert.x
Hi Again.

I have tried this approach, but perhaps I am missing something. I am trying to update the res.result() which is supposed to be a JsonArray, but when res.result() is null, I have no 
way of doing that. So res.result().add is not possible. 

I don’t know if I’m explaining it sufficiently, but this code is invalid. 

    sd.<String, JsonArray>getClusterWideMap("nodes", res -> {
      if (res.succeeded()) {

        // get the map
        AsyncMap<String, JsonArray> nodesMap = res.result();

        //
        JsonArray myObject = new JsonArray();

        // create the nodes object if its missing
        nodesMap.putIfAbsent("nodesList", myObject, res2 -> {
          if (res.succeeded()) {
            JsonArray obj = res.result();
            if (obj == null) {
              obj = myObject;
            }
            obj.add(uniqueAddress);
            // how do I update res2.result() since its null?
          }
        });

      } else {
        logger.warn("No clusterwide map support");
      }

    });



Kegan Holtzhausen

unread,
Mar 22, 2016, 10:28:31 AM3/22/16
to vert.x
This is the working code I can come up with, but I still have to get the map twice.

    sd.<String, JsonArray>getClusterWideMap("nodes", getMap -> {
      if (getMap.succeeded()) {

        // get the map
        AsyncMap<String, JsonArray> nodesMap = getMap.result();

        // create the nodes object if its missing
        nodesMap.putIfAbsent("nodesList", new JsonArray(), newList -> {
          if (newList.succeeded()) {
            // this will actually update the list
            nodesMap.get("nodesList", updateList -> {
              if (updateList.succeeded()) {
                updateList.result().add(uniqueAddress);
              }
            });

          }
        });

      } else {
        logger.warn("No clusterwide map support");
      }

    });

Tim Fox

unread,
Mar 22, 2016, 11:12:14 AM3/22/16
to ve...@googlegroups.com
I'm not really sure I'm understanding your use case, but if you want to create an initial nodes list only if it's not already there why don't you just set it up before the call to putIfAbsent? e.g.

JsonArray nodesList = new JsonArray();

nodesList.add(blah); // set up with initial values

nodesMap.putIfAbsent("nodesList", nodesList, ...);
Reply all
Reply to author
Forward
0 new messages