Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-2005

Integer overflow with upsert

    • Type: Icon: Bug Bug
    • Resolution: Done
    • Priority: Icon: Major - P3 Major - P3
    • 1.7.3
    • Affects Version/s: 1.6.3
    • Component/s: Write Ops
    • None
    • Environment:
      MongoDB v1.6.3, 64-bit builds on 64-bit Linux (Ubuntu 10.4)
    • ALL

      I'm having an issue that I can only assume is a 32-bit integer overflow issue. I'm running on 64-bit Linux boxes with the 64-bit builds of MongoDB v1.6.3.

      Here's the deal:

      I have a collection used for logging and aggregate counters. I'm using an upsert with $inc to increment these counters. When the counters get over 2^31, it rolls over to negative.

      I've been able to reproduce it with the ruby driver:

      require 'rubygems'
      require 'mongo'

      mongo = Mongo::Connection.new "localhost"
      db = mongo.db "test"

      db.collection('junk').drop
      (0..20).each do |i|
      db.collection('junk').update({:name=>'luke'}, {"$inc"=>{:total=>123456789}}, {:upsert=>true})
      puts db.collection('junk').find({}, {:fields=>{:_id=>0}}).to_a.inspect
      end

      and that outputs: (I've bolded the line where it flips negative)

      [

      {"name"=>"luke", "total"=>123456789}

      ]
      [

      {"name"=>"luke", "total"=>246913578}

      ]
      [

      {"name"=>"luke", "total"=>370370367}

      ]
      [

      {"name"=>"luke", "total"=>493827156}

      ]
      [

      {"name"=>"luke", "total"=>617283945}

      ]
      [

      {"name"=>"luke", "total"=>740740734}

      ]
      [

      {"name"=>"luke", "total"=>864197523}

      ]
      [

      {"name"=>"luke", "total"=>987654312}

      ]
      [

      {"name"=>"luke", "total"=>1111111101}

      ]
      [

      {"name"=>"luke", "total"=>1234567890}

      ]
      [

      {"name"=>"luke", "total"=>1358024679}

      ]
      [

      {"name"=>"luke", "total"=>1481481468}

      ]
      [

      {"name"=>"luke", "total"=>1604938257}

      ]
      [

      {"name"=>"luke", "total"=>1728395046}

      ]
      [

      {"name"=>"luke", "total"=>1851851835}

      ]
      [

      {"name"=>"luke", "total"=>1975308624}

      ]
      [

      {"name"=>"luke", "total"=>2098765413}

      ]
      [

      {"name"=>"luke", "total"=>-2072745094}

      ]
      [

      {"name"=>"luke", "total"=>-1949288305}

      ]
      [

      {"name"=>"luke", "total"=>-1825831516}

      ]
      [

      {"name"=>"luke", "total"=>-1702374727}

      ]

      I suspect that initially MongoDB is storing the integer using the 4-byte integer data type, but when my upsert increments it, it isn't converted to the 8-byte integer.

      Just for fun, I tried upserting a large number and it indeed is stored just fine (I suspect it is created as an 8-byte integer):

      db.collection('junk').drop
      db.collection('junk').update({:name=>'luke'}, {"$inc"=>{:total=>9999999999999}}, {:upsert=>true})
      puts db.collection('junk').find({}, {:fields=>{:_id=>0}}).to_a.inspect

      and that outputs (which is clearly an 8-byte integer):

      [

      {"name"=>"luke", "total"=>9999999999999}

      ]

            Assignee:
            eliot Eliot Horowitz (Inactive)
            Reporter:
            lehresman Luke Ehresman
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: