   (when-not (describe-table creds table-name)
     (apply create-table creds table-name opts)))
 
+(defn- throughput-steps
+  "Dec by any amount, inc by <= 2x current amount, Ref. http://goo.gl/Bj9TC.
+  x - start, x' - current, x* - goal."
+  [[r w] [r* w*]]
+  (let [step (fn [x* x'] (if (< x* x') x* (min x* (* 2 x'))))]
+    (loop [steps [] [r' w'] [r w]]
+      (if (and (>= r' r*) (>= w' w*))
+        steps
+        (let [[r' w' :as this-step] [(step r* r') (step w* w')]]
+          (recur (conj steps this-step) this-step))))))
+
+(comment (throughput-steps [1 1] [1 1])
+         (throughput-steps [1 1] [12 12])
+         (throughput-steps [3 3] [27 27])
+         (throughput-steps [17 8] [3 22])
+         (throughput-steps [1 1] [300 300]))
+
 (defn update-table
-  "Updates a table. Ref. http://goo.gl/Bj9TC for important throughput
-  upgrade/downgrade limits."
-  [creds {table-name :name :keys [throughput]}]
-  (as-map
-   (.updateTable (db-client creds)
-     (doto-maybe (UpdateTableRequest.) g
-       table-name (.setTableName (name g))
-       throughput (.setProvisionedThroughput (provisioned-throughput g))))))
+  "Updates a table. Allows automatic multi-step adjustments to conform to
+  update limits, Ref. http://goo.gl/Bj9TC.
+
+  Returns a promise to which the final resulting table description will be
+  delivered. Deref this promise to block until update (all steps) complete."
+  [creds table throughput & [{:keys [max-reqs]
+                              :or   {max-reqs 5}}]]
+  (let [{read* :read write* :write} throughput
+        {:keys [status throughput]} (describe-table creds table)
+        {:keys [read write num-decreases-today]} throughput
+
+        decreasing? (or (< read* read) (< write* write))
+        steps  (throughput-steps [read write] [read* write*])
+        nsteps (count steps)]
+    (when-not (empty? steps)
+      (cond (not= status :active)
+            (throw (Exception. (str "Invalid table status: " status)))
+            (and decreasing? (>= num-decreases-today 4)) ; API limit
+            (throw (Exception. (str "Max 4 decreases per 24hr period")))
+            (> nsteps max-reqs)
+            (throw (Exception. (str "`max-reqs` too low, needs reqs: " nsteps)))
+            :else
+            (letfn [(run1 [[r' w']]
+                      (as-map
+                       (.updateTable (db-client creds)
+                         (doto (UpdateTableRequest.)
+                           (.setTableName (name table))
+                           (.setProvisionedThroughput (provisioned-throughput
+                                                       {:read r' :write w'})))))
+                      ;; Returns _new_ descr when ready:
+                      (block-while-table-status creds table :updating))]
+
+              (let [p (promise)]
+                (future (deliver p (peek (mapv run1 steps))))
+                p))))))
+
+(comment
+  (def dt (describe-table creds :faraday.tests.main))
+  (let [p (update-table creds :faraday.tests.main {:read 1 :write 1})]
+    @p))
 
 (defn delete-table "Deletes a table, go figure."
   [creds table]

             (.setLocalSecondaryIndexes (local-indexes hash-keydef indexes)))))]

    (if-not block?
      request-result
      (do (block-while-table-status creds table-name :creating)
          request-result))))

(comment (time (create-table mc "delete-me7" [:id :s] {:block? true})))


  [creds table-name hash-keydef
   & [{:keys [range-keydef throughput indexes block?]
       :or   {throughput {:read 1 :write 1}}}]]
  (let [result
        (as-map
         (.createTable (db-client creds)
           (doto (CreateTableRequest.)
