Uploaded image for project: 'WiredTiger'
  1. WiredTiger
  2. WT-409

an empty value column subset when opening a cursor on an index drops core

    • Type: Icon: Task Task
    • Resolution: Done
    • WT1.4.1
    • Affects Version/s: None
    • Component/s: None

      Michael, if you specify an empty value column subset to an index, WT drops core.

      Here's the test program, ripped out of examples/c/ex_schema.c:

      #include <wiredtiger.h>
      
      const char *home = "WT_TEST";
      
      /*! [schema declaration] */
      /* The C struct for the data we are storing in a WiredTiger table. */
      typedef struct {
              char country[5];
              unsigned short year;
              unsigned long long population;
      } POP_RECORD;
      
      POP_RECORD pop_data[] = {
              { "AU",  1900,    4000000 },
              { "AU",  2000,   19053186 },
              { "CAN", 1900,    5500000 },
              { "CAN", 2000,   31099561 },
              { "UK",  1900,  369000000 },
              { "UK",  2000,   59522468 },
              { "USA", 1900,   76212168 },
              { "USA", 2000,  301279593 },
              { "", 0, 0 }
      };
      /*! [schema declaration] */
      
      int
      main(void)
      {
              POP_RECORD *p;
              WT_CONNECTION *conn;
              WT_CURSOR *cursor;
              WT_SESSION *session;
              unsigned short year;
              const char *country;
              int ret;
      
              system("rm -rf WT_TEST && mkdir WT_TEST");
              ret = wiredtiger_open(home, NULL, "create", &conn);
              ret = conn->open_session(conn, NULL, NULL, &session);
              ret = session->create(session, "table:mytable",
                  "key_format=r,"
                  "value_format=5sHQ,"
                  "columns=(id,country,year,population)");
              ret = session->create(session,
                  "index:mytable:country_plus_year", "columns=(country,year)");
              ret = session->open_cursor(
                  session, "table:mytable", NULL, "append", &cursor);
              for (p = pop_data; p->year != 0; p++) {
                      cursor->set_value(cursor, p->country, p->year, p->population);
                      ret = cursor->insert(cursor);
              }
              ret = cursor->close(cursor);
              ret = session->open_cursor(session,
                  "index:mytable:country_plus_year()", NULL, NULL, &cursor);
              while ((ret = cursor->next(cursor)) == 0) {
                      cursor->get_key(cursor, &country, &year);
                      printf("country %s, year %u\n", country, year);
              }
      
              ret = conn->close(conn, NULL);
              return (ret);
      }
      

      The interesting line is:

      ret = session->open_cursor(session,
                  "index:mytable:country_plus_year()", NULL, NULL, &cursor);
      

      If you change it to:

      ret = session->open_cursor(session,
                  "index:mytable:country_plus_year(year)", NULL, NULL, &cursor);
      

      it works.

      The stack is:

      0x000000000044867c in __curindex_close (cursor=0x800c72b00)
          at ../src/cursor/cur_index.c:281
      281			if (*cp != NULL) {
      (gdb) where
      #0  0x000000000044867c in __curindex_close (cursor=0x800c72b00)
          at ../src/cursor/cur_index.c:281
      WT-1  0x0000000000448e43 in __wt_curindex_open (session=0x800c25430, 
          uri=0x47c0a0 "index:mytable:country_plus_year()", cfg=0x7fffffffe810, 
          cursorp=0x7fffffffe880) at ../src/cursor/cur_index.c:446
      WT-2  0x0000000000414ecb in __wt_open_cursor (session=0x800c25430, 
          uri=0x47c0a0 "index:mytable:country_plus_year()", owner=0x0, 
          cfg=0x7fffffffe810, cursorp=0x7fffffffe880)
          at ../src/session/session_api.c:201
      WT-3  0x000000000041517c in __session_open_cursor (wt_session=0x800c25430, 
          uri=0x47c0a0 "index:mytable:country_plus_year()", to_dup=0x0, config=0x0, 
          cursorp=0x7fffffffe880) at ../src/session/session_api.c:243
      WT-4  0x0000000000402102 in main ()
      

      In summary, at around line 429 of cur_index.c, __wt_curindex_open() calls __wt_struct_reformat() with a "columns" value of "()", and it fails, returning not-found. That jumps to the err: label, which calls __curindex_close(), which has this loop:

              for (i = 0, cp = cindex->cg_cursors;
                  i < WT_COLGROUPS(cindex->table); i++, cp++)
                      if (*cp != NULL) {
                              WT_TRET((*cp)->close(*cp));
                              *cp = NULL;
                      }
              
      

      The table might have a non-zero number of column groups at this point, and even if it doesn't, WT_COLGROUPS returns a minimum value of 1.

      In either case, cp == NULL and *cp drops core.

      Sorry I'm dumping this to you, but I stared at it for a little while, and I wasn't sure what the right fix should be.

            Assignee:
            michael.cahill@mongodb.com Michael Cahill (Inactive)
            Reporter:
            keith.bostic@mongodb.com Keith Bostic (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: