# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You # may not use this file except in compliance with the License. A copy of # the License is located at # # http://aws.amazon.com/apache2.0/ # # or in the "license" file accompanying this file. This file is # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. require 'aws-sdk' module Aws::SessionStore::DynamoDB # Collects and deletes unwanted sessions based on # their creation and update dates. module GarbageCollection module_function # Scans DynamoDB session table to find # sessions that match the max age and max stale period # requirements. it then deletes all of the found sessions. def collect_garbage(options = {}) config = load_config(options) last_key = eliminate_unwanted_sessions(config) while !last_key.empty? last_key = eliminate_unwanted_sessions(config, last_key) end end # Loads configuration options. # @option (see Configuration#initialize) # @api private def load_config(options = {}) Aws::SessionStore::DynamoDB::Configuration.new(options) end # Sets scan filter attributes based on attributes specified. # @api private def scan_filter(config) hash = {} hash['created_at'] = oldest_date(config.max_age) if config.max_age hash['updated_at'] = oldest_date(config.max_stale) if config.max_stale { :scan_filter => hash } end # Scans and deletes batch. # @api private def eliminate_unwanted_sessions(config, last_key = nil) scan_result = scan(config, last_key) batch_delete(config, scan_result[:member]) scan_result[:last_evaluated_key] || {} end # Scans the table for sessions matching the max age and # max stale time specified. # @api private def scan(config, last_item = nil) options = scan_opts(config) options = options.merge(start_key(last_item)) if last_item config.dynamo_db_client.scan(options) end # Deletes the batch gotten from the scan result. # @api private def batch_delete(config, items) begin subset = items.shift(25) sub_batch = write(subset) process!(config, sub_batch) end until subset.empty? end # Turns array into correct format to be passed in to # a delete request. # @api private def write(sub_batch) sub_batch.inject([]) do |rqst_array, item| rqst_array << {:delete_request => {:key => item}} rqst_array end end # Proccesses pending request items. # @api private def process!(config, sub_batch) return if sub_batch.empty? opts = {} opts[:request_items] = {config.table_name => sub_batch} begin response = config.dynamo_db_client.batch_write_item(opts) opts[:request_items] = response[:unprocessed_items] end until opts[:request_items].empty? end # Provides scan options. # @api private def scan_opts(config) table_opts(config).merge(scan_filter(config)) end # Provides table options # @api private def table_opts(config) { :table_name => config.table_name, :attributes_to_get => [config.table_key] } end # @return [Hash] Hash with specified date attributes. # @api private def oldest_date(sec) hash = {} hash[:attribute_value_list] = [:n => "#{((Time.now - sec).to_f)}"] hash[:comparison_operator] = 'LT' hash end # Provides start key. # @api private def start_key(last_item) { :exclusive_start_key => last_item } end end end