Class: EventMachine::Couchdb::LoadTesting::Agent

Inherits:
Object
  • Object
show all
Defined in:
lib/em-couchdb-request/load_testing/agent.rb

Constant Summary collapse

DEFAULT_OPTIONS =
{
  :content_size => 1024 * 1,    # size of random bytes written to a random document in the database
  :push_interval => 20,         # interval between PUSH
  :poll_interval => 0.001,      # interval between generating POLL connections - control the creating speed
  :poll_max_count => 2500,      # count of the total POLL connections
  :poll_bulk_count => 500,      # size of a POLL GROUP - that is created continously (step by POLL_INTERVAL)
  :poll_bulk_interval => 1200   # interval between POLL GROUP (or continue by pressing any key)
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(uri, name, opts = {}) ⇒ Agent

Returns a new instance of Agent.



30
31
32
33
34
35
36
37
38
39
40
# File 'lib/em-couchdb-request/load_testing/agent.rb', line 30

def initialize(uri, name, opts={})
  @server = EventMachine::Couchdb::Server.new uri, opts
  @db = @server.em_database(name)
  @docs = []

  @max_id = 0
  @count = 0
  @lock = false
  
  @options = DEFAULT_OPTIONS.merge(opts[:agent_options])
end

Instance Attribute Details

#lockObject

lock to disable creating new poll connection



28
29
30
# File 'lib/em-couchdb-request/load_testing/agent.rb', line 28

def lock
  @lock
end

Instance Method Details

#pollObject



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/em-couchdb-request/load_testing/agent.rb', line 74

def poll
  # http://eventmachine.rubyforge.org/docs/EPOLL.html
  EM.epoll
      
  EM.run {
    EM.open_keyboard(KeyboardHandler, self)
    
    @server.get_db(@db.name) { |resp|
      # ensure to get something for feedback when connection
      seq = resp["update_seq"] - 1

      # auto continue for each POLL_BULK_INTERVAL
      b_timer = nil
      if @options[:poll_bulk_interval] > 0
        b_timer = EM.add_periodic_timer(@options[:poll_bulk_interval]) {
          @lock = false
        }
      end
      
      puts ">> Start to poll from #{@db.base_uri} (since #{seq}) every #{@options[:poll_interval]} seconds ..."
  
      timer = EM.add_periodic_timer(@options[:poll_interval]) {
        new_poll_request(:seq => seq) unless @lock

        if @max_id % @options[:poll_bulk_count] == 0
          @lock = true 
        end
    
        if @max_id >= @options[:poll_max_count]
          timer.cancel
          b_timer.try(:cancel)
        end
      }
    }
  }
end

#pushObject



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/em-couchdb-request/load_testing/agent.rb', line 42

def push
  EM.run {
    @db.all_docs { |resp|
      @docs = resp["rows"].collect{ |row| row["id"] }
    }

    puts ">> Start to push to #{@db.base_uri} every #{@options[:push_interval]} seconds ..."

    EM.add_periodic_timer(@options[:push_interval]) {
      #
      # --- why get the doc first before updating ---
      #
      # To update an existing document, you also issue a PUT request.
      # In this case, the JSON body must contain a _rev property, which lets CouchDB know which revision the edits are based on.
      # If the revision of the document currently stored in the database doesn't match, then a 409 conflict error is returned.
      begin
        start_at = Time.now
        @db.doc(@docs.sample) { |resp|
          # set the new content
          resp[:random_bytes] = SecureRandom.hex(@options[:content_size])
          # update doc and record the latest revision
          @db.save_doc(resp) { |resp|
            @db.log "PUSH\t#{@options[:content_size]}\t#{resp["rev"]}", start_at
          }
        }
      rescue
        @db.log "PUSH\t#{@options[:content_size]}\t#{resp["rev"]}", start_at
      end
    }
  }
end